detached proxy negociation code from pqisslproxy so as to use it in FriendServer as well

This commit is contained in:
csoler 2022-01-09 15:22:47 +01:00
parent 896762b948
commit 2456dbb2a0
6 changed files with 564 additions and 514 deletions

View File

@ -127,9 +127,6 @@ bool FsClient::sendItem(const std::string& address,uint16_t port,RsItem *item,st
RsSerialiser *rss = new RsSerialiser(); // deleted by ~pqistreamer()
rss->addSerialType(fss);
// FsSerializer().serialise(item,data,&size);
// write(CreateSocket,data,size); // shouldn't we use the pqistreamer in R/W mode instead?
RsFdBinInterface *bio = new RsFdBinInterface(CreateSocket,true); // deleted by ~pqistreamer()
pqithreadstreamer p(this,rss,RsPeerId(),bio,BIN_FLAGS_READABLE | BIN_FLAGS_WRITEABLE | BIN_FLAGS_NO_CLOSE);

View File

@ -399,6 +399,7 @@ HEADERS += pqi/authssl.h \
pqi/pqissl.h \
pqi/pqissllistener.h \
pqi/pqisslpersongrp.h \
pqi/pqiproxy.h \
pqi/pqisslproxy.h \
pqi/pqistore.h \
pqi/pqistreamer.h \
@ -571,6 +572,7 @@ SOURCES += pqi/authgpg.cc \
pqi/pqissl.cc \
pqi/pqissllistener.cc \
pqi/pqisslpersongrp.cc \
pqi/pqiproxy.cc \
pqi/pqisslproxy.cc \
pqi/pqistore.cc \
pqi/pqistreamer.cc \

View File

@ -0,0 +1,467 @@
#include "util/rsdebug.h"
#include "util/rsnet.h"
#include "pqi/pqiproxy.h"
//#define PROXY_DEBUG 1
int pqiproxyconnection::proxy_negotiate_connection(int sockfd)
{
int ret = 0;
switch(mProxyState)
{
case PROXY_STATE_INIT:
ret = Proxy_Send_Method(sockfd); // checks basic conn, sends Method when able.
break;
case PROXY_STATE_WAITING_METHOD_RESPONSE:
ret = Proxy_Send_Address(sockfd); // waits for Method Response, send Address when able.
break;
case PROXY_STATE_WAITING_SOCKS_RESPONSE:
ret = Proxy_Connection_Complete(sockfd); // 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
return -1;
}
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Basic_Connection_Complete() IN PROGRESS";
std::cerr << std::endl;
#endif
// In Progress.
return 0;
}
int pqiproxyconnection::Proxy_Send_Method(int sockfd)
{
#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 pqiproxyconnection::Proxy_Method_Response(int sockfd)
{
#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 pqiproxyconnection::Proxy_Send_Address(int sockfd)
{
#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(sockfd);
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 pqiproxyconnection::Proxy_Connection_Complete(int sockfd)
{
/* 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;
}

View File

@ -0,0 +1,70 @@
/*******************************************************************************
* libretroshare/src/pqi: pqiproxy.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2004-2013 by Robert Fernie. *
* Copyright 2004-2021 by retroshare team <retroshare.project@gmail.com> *
* *
* This program 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, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program 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 program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <string>
class pqiproxyconnection
{
public:
enum ProxyState: uint8_t {
PROXY_STATE_FAILED = 0x00,
PROXY_STATE_INIT = 0x01,
PROXY_STATE_WAITING_METHOD_RESPONSE = 0x02,
PROXY_STATE_WAITING_SOCKS_RESPONSE = 0x03,
PROXY_STATE_CONNECTION_COMPLETE = 0x04
};
/*!
* \brief proxy_negotiate_connection
* Negotiate the connection with the proxy that is connected with openned socket sockfd. The caller needs to
* connect the socket *before* trying to call proxy_negotiate_connection(). The function must be called as many times as
* necessary until it returns 1 (success) or -1 (error) in which case the socket needs to be closed.
* \return
* -1 : error. The socket must be closed as soon as possible.
* 0 : in progress. The function needs to be called again asap.
* 1 : proxy connection is fully negociated. Client can send data to the socket.
*/
int proxy_negotiate_connection(int sockfd);
void setRemotePort(uint16_t v) { mRemotePort = v; }
void setRemoteAddress(const std::string& s) { mDomainAddress = s; }
ProxyState proxyConnectionState() const { return mProxyState ; }
void proxy_init() { mProxyState = PROXY_STATE_INIT; }
private:
ProxyState mProxyState;
std::string mDomainAddress;
uint16_t mRemotePort;
// These are the internal steps in setting up the Proxy Connection.
int Proxy_Send_Method(int sockfd);
int Proxy_Method_Response(int sockfd);
int Proxy_Send_Address(int sockfd);
int Proxy_Connection_Complete(int sockfd);
};

View File

@ -38,12 +38,6 @@ static struct RsLog::logInfo pqisslproxyzoneInfo = {RsLog::Default, "pqisslproxy
// #define PROXY_DEBUG 1
// #define PROXY_DEBUG_LOG 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)
{
@ -74,7 +68,7 @@ int pqisslproxy::Initiate_Connection()
rslog(RSL_DEBUG_BASIC, pqisslproxyzone,
"pqisslproxy::Initiate_Connection() Connection to Proxy");
/* init proxy state */
mProxyState = PROXY_STATE_INIT;
proxy_init();
/* call standard Init_Conn() */
return pqissl::Initiate_Connection();
@ -98,486 +92,18 @@ int pqisslproxy::Basic_Connection_Complete()
return -1;
}
int ret = 0;
switch(mProxyState)
{
case PROXY_STATE_INIT:
ret = Proxy_Send_Method(); // checks basic conn, sends Method when able.
break;
int ret;
case PROXY_STATE_WAITING_METHOD_RESPONSE:
ret = Proxy_Send_Address(); // waits for Method Response, send Address when able.
break;
if(proxyConnectionState() == PROXY_STATE_INIT && 1!=(ret=pqissl::Basic_Connection_Complete()))
return ret; // basic connection not complete.
case PROXY_STATE_WAITING_SOCKS_RESPONSE:
ret = Proxy_Connection_Complete(); // wait for ACK.
break;
ret = proxy_negotiate_connection(sockfd);
case PROXY_STATE_CONNECTION_COMPLETE:
if(ret < 0)
reset_locked();
#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;
}
return ret;
}
bool pqisslproxy::connect_parameter(uint32_t type, const std::string &value)
{
@ -591,7 +117,7 @@ bool pqisslproxy::connect_parameter(uint32_t type, const std::string &value)
#ifdef PROXY_DEBUG_LOG
rslog(RSL_WARNING, pqisslproxyzone, out);
#endif
mDomainAddress = value;
setRemoteAddress(value);
#ifdef PROXY_DEBUG
std::cerr << out << std::endl;
#endif
@ -614,7 +140,7 @@ bool pqisslproxy::connect_parameter(uint32_t type, uint32_t value)
#ifdef PROXY_DEBUG_LOG
rslog(RSL_WARNING, pqisslproxyzone, out);
#endif
mRemotePort = value;
setRemotePort(value);
#ifdef PROXY_DEBUG
std::cerr << out << std::endl;
#endif

View File

@ -24,6 +24,7 @@
// operating system specific network header.
#include "pqi/pqinetwork.h"
#include "pqi/pqiproxy.h"
#include <string>
#include <map>
@ -39,40 +40,27 @@
* fns declared here are different -> all others are identical.
*/
class pqisslproxy: public pqissl
class pqisslproxy: public pqissl, public pqiproxyconnection
{
public:
pqisslproxy(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm);
virtual ~pqisslproxy();
pqisslproxy(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm);
virtual ~pqisslproxy();
// NetInterface. Is the same.
// BinInterface. Is the same.
// NetInterface. Is the same.
// BinInterface. Is the same.
virtual bool connect_parameter(uint32_t type, const std::string &value);
virtual bool connect_parameter(uint32_t type, uint32_t value);
virtual bool connect_parameter(uint32_t type, const std::string &value);
virtual bool connect_parameter(uint32_t type, uint32_t value);
protected:
//Initiate is the same - except it uses the Proxy Address rather than the Peer Address.
// minor tweaks to setup data state.
virtual int Initiate_Connection();
//Initiate is the same - except it uses the Proxy Address rather than the Peer Address.
// minor tweaks to setup data state.
virtual int Initiate_Connection();
// The real overloading is done in Basic Connection Complete.
// Instead of just checking for an open socket, we need to communicate with the SOCKS5 proxy.
virtual int Basic_Connection_Complete();
// These are the internal steps in setting up the Proxy Connection.
virtual int Proxy_Send_Method();
virtual int Proxy_Method_Response();
virtual int Proxy_Send_Address();
virtual int Proxy_Connection_Complete();
private:
uint32_t mProxyState;
std::string mDomainAddress;
uint16_t mRemotePort;
// The real overloading is done in Basic Connection Complete.
// Instead of just checking for an open socket, we need to communicate with the SOCKS5 proxy.
virtual int Basic_Connection_Complete();
};
#endif // MRK_PQI_SSL_PROXY_HEADER