Files
SingularityViewer/indra/llmessage/llsocks5.cpp
2010-04-02 02:48:44 -03:00

211 lines
6.4 KiB
C++

/**
* @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;
mNeedUpdate = false;
}
// Perform a Socks5 authentication and UDP assioacation to the proxy
// specified by proxy, and assiocate UDP port message_port
int LLSocks::proxyHandshake(LLHost proxy, U32 message_port)
{
int result;
/* Socks 5 Auth request */
socks_auth_request_t socks_auth_request;
socks_auth_response_t socks_auth_response;
socks_auth_request.version = SOCKS_VERSION; // Socks version 5
socks_auth_request.num_methods = 1; // Sending 1 method
socks_auth_request.methods = mAuthMethodSelected; // send only the selected metho
result = tcp_handshake(hProxyControlChannel, (char*)&socks_auth_request, sizeof(socks_auth_request_t), (char*)&socks_auth_response, sizeof(socks_auth_response_t));
if (result != 0)
{
llwarns << "Socks authentication request failed, error on TCP control channel : " << result << llendl;
stopProxy();
return SOCKS_CONNECT_ERROR;
}
if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE)
{
llwarns << "Socks5 server refused all our authentication methods" << llendl;
stopProxy();
return SOCKS_NOT_ACCEPTABLE;
}
// SOCKS5 USERNAME/PASSWORD authentication
if (socks_auth_response.method == METHOD_PASSWORD)
{
// The server has requested a username/password combination
U32 request_size = mSocksUsername.size() + mSocksPassword.size() + 3;
char * password_auth = (char *)malloc(request_size);
password_auth[0] = 0x01;
password_auth[1] = mSocksUsername.size();
memcpy(&password_auth[2],mSocksUsername.c_str(), mSocksUsername.size());
password_auth[mSocksUsername.size()+2] = mSocksPassword.size();
memcpy(&password_auth[mSocksUsername.size()+3], mSocksPassword.c_str(), mSocksPassword.size());
authmethod_password_reply_t password_reply;
result = tcp_handshake(hProxyControlChannel, password_auth, request_size, (char*)&password_reply, sizeof(authmethod_password_reply_t));
free (password_auth);
if (result != 0)
{
llwarns << "Socks authentication failed, error on TCP control channel : " << result << llendl;
stopProxy();
return SOCKS_CONNECT_ERROR;
}
if (password_reply.status != AUTH_SUCCESS)
{
llwarns << "Socks authentication failed" << llendl;
stopProxy();
return SOCKS_AUTH_FAIL;
}
}
/* SOCKS5 connect request */
socks_command_request_t connect_request;
socks_command_response_t connect_reply;
connect_request.version = SOCKS_VERSION; //Socks V5
connect_request.command = COMMAND_UDP_ASSOCIATE; // Associate UDP
connect_request.flag = FIELD_RESERVED;
connect_request.atype = ADDRESS_IPV4;
connect_request.address = 0; // 0.0.0.0 We are not fussy about address
//UDP is promiscious receive for our protocol
connect_request.port = htons(message_port); // Port must be in network byte order
result = tcp_handshake(hProxyControlChannel, (char*)&connect_request, sizeof(socks_command_request_t), (char*)&connect_reply, sizeof(socks_command_response_t));
if (result != 0)
{
llwarns << "Socks connect request failed, error on TCP control channel : " << result << llendl;
stopProxy();
return SOCKS_CONNECT_ERROR;
}
if (connect_reply.reply != REPLY_REQUEST_GRANTED)
{
//Something went wrong
llwarns << "Connection to SOCKS5 server failed, UDP forward request not granted" << llendl;
stopProxy();
return SOCKS_UDP_FWD_NOT_GRANTED;
}
mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
mUDPProxy.setAddress(proxy.getAddress());
// All good now we have been given the UDP port to send requests that need forwarding.
llinfos << "Socks 5 UDP proxy connected on " << mUDPProxy << llendl;
return SOCKS_OK;
}
int LLSocks::startProxy(LLHost proxy, U32 message_port)
{
int status;
mTCPProxy = proxy;
mNeedUpdate = false;
stopProxy();
hProxyControlChannel = tcp_open_channel(proxy);
if (hProxyControlChannel == -1)
{
return SOCKS_HOST_CONNECT_FAILED;
}
status = proxyHandshake(proxy, message_port);
if (status == SOCKS_OK)
{
sUdpProxyEnabled=true;
}
return status;
}
int LLSocks::startProxy(std::string host, U32 port)
{
mTCPProxy.setHostByName(host);
mTCPProxy.setPort(port);
return startProxy(mTCPProxy, (U32)gMessageSystem->mPort);
}
void LLSocks::stopProxy()
{
sUdpProxyEnabled = false;
if (hProxyControlChannel)
{
tcp_close_channel(hProxyControlChannel);
}
}
void LLSocks::setAuthNone()
{
mAuthMethodSelected = METHOD_NOAUTH;
}
void LLSocks::setAuthPassword(std::string username, std::string password)
{
mAuthMethodSelected = METHOD_PASSWORD;
mSocksUsername = username;
mSocksPassword = password;
}
void LLSocks::EnableHttpProxy(LLHost httpHost, LLHttpProxyType type)
{
sHttpProxyEnabled = true;
mHTTPProxy = httpHost;
mProxyType = type;
}