RetroShare/libretroshare/src/pqi/pqisslproxy.cc
csoler f6db432c74 Merge of branch v0.6-rssocialnet 7419 to 7488. Changes from electron and myself:
- added possibility to modify groups (e.g. edit circles)
- fixed mismatched free/delete in fimonitor.cc, authssl.cc, pqibin.cc (saving encrypted hash cache file)
- improved plugin interface class to allow plugins to access GXS objects.
- added method to un-register notify clients from RsNotify
- fixed pqisslproxy for windows, due to win not properly supporting sockets in non blocking mode.
- removed static members form RsInitConfig and made RsAccounts object a pointer. This prevents plugin initialisation problems at symbol resolving time.
- removed bool return from p3IdService::getOwnIds()



git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@7492 b45a01b8-16f6-495d-af2f-9b41ad6348cc
2014-08-25 21:07:07 +00:00

628 lines
15 KiB
C++
Executable File

/*
* pqisslproxy.cc
*
* 3P/PQI network interface for RetroShare.
*
* Copyright 2004-2013 by Robert Fernie.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 2.1 as published by the Free Software Foundation.
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Please report all bugs and problems to "retroshare@lunamutt.com".
*
*/
#include "pqi/pqisslproxy.h"
#include "pqi/pqinetwork.h"
#include <errno.h>
#include <openssl/err.h>
#include <sstream>
#include "util/rsdebug.h"
#include "util/rsnet.h"
#include "pqi/p3linkmgr.h"
const int pqisslproxyzone = 3517;
#define PROXY_DEBUG 1
#define PROXY_STATE_FAILED 0
#define PROXY_STATE_INIT 1
#define PROXY_STATE_WAITING_METHOD_RESPONSE 2
#define PROXY_STATE_WAITING_SOCKS_RESPONSE 3
#define PROXY_STATE_CONNECTION_COMPLETE 4
pqisslproxy::pqisslproxy(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm)
:pqissl(l, parent, lm)
{
sockaddr_storage_clear(remote_addr);
return;
}
pqisslproxy::~pqisslproxy()
{
rslog(RSL_ALERT, pqisslproxyzone,
"pqisslproxy::~pqisslproxy -> destroying pqisslproxy");
stoplistening();
reset();
return;
}
int pqisslproxy::Initiate_Connection()
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Initiate_Connection()";
std::cerr << std::endl;
#endif
rslog(RSL_DEBUG_BASIC, pqisslproxyzone,
"pqisslproxy::Initiate_Connection() Connection to Proxy");
/* init proxy state */
mProxyState = PROXY_STATE_INIT;
/* call standard Init_Conn() */
return pqissl::Initiate_Connection();
}
/********* VERY DIFFERENT **********/
int pqisslproxy::Basic_Connection_Complete()
{
rslog(RSL_DEBUG_BASIC, pqisslproxyzone,
"pqisslproxy::Basic_Connection_Complete()...");
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Basic_Connection_Complete() STATE: " << mProxyState;
std::cerr << std::endl;
#endif
if (CheckConnectionTimeout())
{
// calls reset.
return -1;
}
int ret = 0;
switch(mProxyState)
{
case PROXY_STATE_INIT:
ret = Proxy_Send_Method(); // checks basic conn, sends Method when able.
break;
case PROXY_STATE_WAITING_METHOD_RESPONSE:
ret = Proxy_Send_Address(); // waits for Method Response, send Address when able.
break;
case PROXY_STATE_WAITING_SOCKS_RESPONSE:
ret = Proxy_Connection_Complete(); // wait for ACK.
break;
case PROXY_STATE_CONNECTION_COMPLETE:
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Basic_Connection_Complete() COMPLETED";
std::cerr << std::endl;
#endif
return 1;
case PROXY_STATE_FAILED:
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Basic_Connection_Complete() FAILED";
std::cerr << std::endl;
#endif
reset_locked();
return -1;
}
if (ret < 0)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Basic_Connection_Complete() FAILED(2)";
std::cerr << std::endl;
#endif
reset_locked();
return -1; // FAILURE.
}
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Basic_Connection_Complete() IN PROGRESS";
std::cerr << std::endl;
#endif
// In Progress.
return 0;
}
int pqisslproxy::Proxy_Send_Method()
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Send_Method() Checking pqissl::Basic_Connection_Complete()";
std::cerr << std::endl;
#endif
int ret = pqissl::Basic_Connection_Complete();
if (ret != 1)
{
return ret; // basic connection not complete.
}
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Send_Method() Basic complete, sending Method";
std::cerr << std::endl;
#endif
/* send hello to proxy server */
char method_hello_data[3] = { 0x05, 0x01, 0x00 }; // [ Ver | nMethods (1) | No Auth Method ]
int sent = send(sockfd, method_hello_data, 3, 0);
if (sent != 3)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Send_Method() Send Failure";
std::cerr << std::endl;
#endif
return -1;
}
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Send_Method() Send Method Okay";
std::cerr << std::endl;
#endif
mProxyState = PROXY_STATE_WAITING_METHOD_RESPONSE;
return 1;
}
int pqisslproxy::Proxy_Method_Response()
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Method_Response()";
std::cerr << std::endl;
#endif
/* get response from proxy server */
char method_response[2];
/*
first it was:
int recvd = recv(sockfd, method_response, 2, MSG_WAITALL);
this does not work on windows, because the socket is in nonblocking mode
the winsock reference says about the recv function and MSG_WAITALL:
"Note that if the underlying transport does not support MSG_WAITALL,
or if the socket is in a non-blocking mode, then this call will fail with WSAEOPNOTSUPP."
now it is a two step process:
int recvd = recv(sockfd, method_response, 2, MSG_PEEK); // test how many bytes are in the input queue
if (enaugh bytes available){
recvd = recv(sockfd, method_response, 2, 0);
}
this does not work on windows:
if ((recvd == -1) && (errno == EAGAIN)) return TRY_AGAIN_LATER;
instead have to do:
if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK)) return TRY_AGAIN_LATER;
*/
// test how many bytes can be read from the queue
int recvd = recv(sockfd, method_response, 2, MSG_PEEK);
if (recvd != 2)
{
#ifdef WINDOWS_SYS
if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK))
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Method_Response() waiting for more data (windows)";
std::cerr << std::endl;
#endif
return 0;
}
#endif
if ((recvd == -1) && (errno == EAGAIN))
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Method_Response() EAGAIN";
std::cerr << std::endl;
#endif
return 0;
}
else if (recvd == -1)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Method_Response() recv error peek";
std::cerr << std::endl;
#endif
return -1;
}
else
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Method_Response() waiting for more data";
std::cerr << std::endl;
#endif
return 0;
}
}
// read the bytes
recvd = recv(sockfd, method_response, 2, 0);
if (recvd != 2)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Method_Response() recv error";
std::cerr << std::endl;
#endif
return -1;
}
// does it make sense?
if (method_response[0] != 0x05)
{
// Error.
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Method_Response() Error response[0] != 0x05. Is: ";
std::cerr << (uint32_t) method_response[0];
std::cerr << std::endl;
#endif
return -1;
}
if (method_response[1] != 0x00)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Method_Response() Error response[0] != 0x00. Is: ";
std::cerr << (uint32_t) method_response[1];
std::cerr << std::endl;
#endif
// Error.
return -1;
}
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Method_Response() Response Okay";
std::cerr << std::endl;
#endif
return 1;
}
#define MAX_SOCKS_REQUEST_LEN 262 // 4 + 1 + 255 + 2.
int pqisslproxy::Proxy_Send_Address()
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Send_Address() Checking Method Response";
std::cerr << std::endl;
#endif
// Check Method Response.
int ret = Proxy_Method_Response();
if (ret != 1)
{
return ret; // Method Response not complete.
}
char socks_request[MAX_SOCKS_REQUEST_LEN] =
{ 0x05, // SOCKS VERSION.
0x01, // CONNECT (Tor doesn't support BIND or UDP).
0x00, // RESERVED.
0x03, // ADDRESS TYPE (Domain Name)
0x00, // Length of Domain name... the rest is variable so can't hard code it!
};
/* get the length of the domain name, pack so we can't overflow uint8_t */
uint8_t len = mDomainAddress.length();
socks_request[4] = len;
for(int i = 0; i < len; i++)
{
socks_request[5 + i] = mDomainAddress[i];
}
/* now add the port, being careful with packing */
uint16_t net_port = htons(mRemotePort);
socks_request[5 + len] = ((uint8_t *) &net_port)[0];
socks_request[5 + len + 1] = ((uint8_t *) &net_port)[1];
int pkt_len = 5 + len + 2;
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Send_Address() Sending String: ";
for(int i = 0; i < pkt_len; i++)
std::cerr << (uint32_t) socks_request[i];
std::cerr << std::endl;
#endif
int sent = send(sockfd, socks_request, pkt_len, 0);
if (sent != pkt_len)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Send_Address() Send Error";
std::cerr << std::endl;
#endif
return -1;
}
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Send_Address() Sent Okay";
std::cerr << std::endl;
#endif
mProxyState = PROXY_STATE_WAITING_SOCKS_RESPONSE;
return 1;
}
int pqisslproxy::Proxy_Connection_Complete()
{
/* get response from proxy server */
/* response is similar format to request - with variable length data */
char socks_response[MAX_SOCKS_REQUEST_LEN];
// test how many bytes can be read
int recvd = recv(sockfd, socks_response, 5, MSG_PEEK);
if (recvd != 5)
{
#ifdef WINDOWS_SYS
if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK))
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data (windows)";
std::cerr << std::endl;
#endif
return 0;
}
#endif
if ((recvd == -1) && (errno == EAGAIN))
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() EAGAIN";
std::cerr << std::endl;
#endif
return 0;
}
else if (recvd == -1)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error peek";
std::cerr << std::endl;
#endif
return -1;
}
else
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data";
std::cerr << std::endl;
#endif
return 0;
}
}
// read the bytes
recvd = recv(sockfd, socks_response, 5, 0);
if (recvd != 5)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error";
std::cerr << std::endl;
#endif
return -1;
}
// error checking.
if (socks_response[0] != 0x05)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR socks_response[0] != 0x05. is: ";
std::cerr << (uint32_t) socks_response[0];
std::cerr << std::endl;
#endif
// error.
return -1;
}
if (socks_response[1] != 0x00)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR socks_response[1] != 0x00. is: ";
std::cerr << (uint32_t) socks_response[1];
std::cerr << std::endl;
#endif
// connection failed.
return -1;
}
int address_bytes = 0;
switch(socks_response[3]) // Address Type.
{
case 0x01:
// IPv4 4 address bytes.
address_bytes = 4;
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() IPv4 Address Type";
std::cerr << std::endl;
#endif
break;
case 0x04:
// IPv6 16 address bytes.
address_bytes = 16;
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() IPv6 Address Type";
std::cerr << std::endl;
#endif
break;
case 0x03:
// Variable address bytes - specified in next byte.
address_bytes = 1 + socks_response[4];
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() Domain Address Type. len: " << address_bytes;
std::cerr << std::endl;
#endif
break;
default:
// unknown error.
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR Unknown Address Type";
std::cerr << std::endl;
#endif
return -1;
break;
}
// test how many bytes can be read
recvd = recv(sockfd, &(socks_response[5]), address_bytes + 1, MSG_PEEK); // address_bytes - 1 + 2...
if (recvd != address_bytes + 1)
{
#ifdef WINDOWS_SYS
if((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK))
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data(2) (windows)";
std::cerr << std::endl;
#endif
return 0;
}
#endif
if ((recvd == -1) && (errno == EAGAIN))
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR EAGAIN at end.";
std::cerr << std::endl;
#endif
// Waiting - shouldn't happen.
return 0;
}
else if (recvd == -1)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR recving(2)";
std::cerr << std::endl;
#endif
return -1;
}
else
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data(2)";
std::cerr << std::endl;
#endif
return 0;
}
}
// read the bytes
recvd = recv(sockfd, &(socks_response[5]), address_bytes + 1, 0); // address_bytes - 1 + 2...
if (recvd != address_bytes + 1)
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error (2)";
std::cerr << std::endl;
#endif
return -1;
}
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Connection_Complete() Received String: ";
for(int i = 0; i < 4 + address_bytes + 2; i++)
std::cerr << (uint32_t) socks_response[i];
std::cerr << std::endl;
#endif
// should print address.
// if we get here - connection is good!.
mProxyState = PROXY_STATE_CONNECTION_COMPLETE;
return 1;
}
bool pqisslproxy::connect_parameter(uint32_t type, const std::string &value)
{
{
RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/
if (type == NET_PARAM_CONNECT_DOMAIN_ADDRESS)
{
std::string out;
rs_sprintf(out, "pqisslproxy::connect_parameter() Peer: %s DOMAIN_ADDRESS: %s", PeerId().toStdString().c_str(), value.c_str());
rslog(RSL_WARNING, pqisslproxyzone, out);
mDomainAddress = value;
std::cerr << out << std::endl;
return true;
}
}
return pqissl::connect_parameter(type, value);
}
bool pqisslproxy::connect_parameter(uint32_t type, uint32_t value)
{
{
RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/
if (type == NET_PARAM_CONNECT_REMOTE_PORT)
{
std::string out;
rs_sprintf(out, "pqisslproxy::connect_parameter() Peer: %s REMOTE_PORT: %lu", PeerId().toStdString().c_str(), value);
rslog(RSL_WARNING, pqisslproxyzone, out);
mRemotePort = value;
std::cerr << out << std::endl;
return true;
}
}
return pqissl::connect_parameter(type, value);
}