From 2456dbb2a0f5dbef2d24535394f71b1330c4fe96 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 9 Jan 2022 15:22:47 +0100 Subject: [PATCH] detached proxy negociation code from pqisslproxy so as to use it in FriendServer as well --- libretroshare/src/friend_server/fsclient.cc | 3 - libretroshare/src/libretroshare.pro | 2 + libretroshare/src/pqi/pqiproxy.cc | 467 ++++++++++++++++++ libretroshare/src/pqi/pqiproxy.h | 70 +++ libretroshare/src/pqi/pqisslproxy.cc | 496 +------------------- libretroshare/src/pqi/pqisslproxy.h | 40 +- 6 files changed, 564 insertions(+), 514 deletions(-) create mode 100644 libretroshare/src/pqi/pqiproxy.cc create mode 100644 libretroshare/src/pqi/pqiproxy.h diff --git a/libretroshare/src/friend_server/fsclient.cc b/libretroshare/src/friend_server/fsclient.cc index ccdd9a019..1da758250 100644 --- a/libretroshare/src/friend_server/fsclient.cc +++ b/libretroshare/src/friend_server/fsclient.cc @@ -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); diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index bc4e6beb5..49c16227f 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -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 \ diff --git a/libretroshare/src/pqi/pqiproxy.cc b/libretroshare/src/pqi/pqiproxy.cc new file mode 100644 index 000000000..2f18cc1a3 --- /dev/null +++ b/libretroshare/src/pqi/pqiproxy.cc @@ -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; + +} + diff --git a/libretroshare/src/pqi/pqiproxy.h b/libretroshare/src/pqi/pqiproxy.h new file mode 100644 index 000000000..121139817 --- /dev/null +++ b/libretroshare/src/pqi/pqiproxy.h @@ -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 * + * * + * 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 . * + * * + *******************************************************************************/ + +#pragma once + +#include + +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); +}; + diff --git a/libretroshare/src/pqi/pqisslproxy.cc b/libretroshare/src/pqi/pqisslproxy.cc index 1c61bef78..750c366fa 100644 --- a/libretroshare/src/pqi/pqisslproxy.cc +++ b/libretroshare/src/pqi/pqisslproxy.cc @@ -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 diff --git a/libretroshare/src/pqi/pqisslproxy.h b/libretroshare/src/pqi/pqisslproxy.h index dc34295ad..7071f4dfb 100644 --- a/libretroshare/src/pqi/pqisslproxy.h +++ b/libretroshare/src/pqi/pqisslproxy.h @@ -24,6 +24,7 @@ // operating system specific network header. #include "pqi/pqinetwork.h" +#include "pqi/pqiproxy.h" #include #include @@ -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