Merge pull request #2495 from csoler/v0.6-FriendServer

V0.6 friend server
This commit is contained in:
csoler 2022-01-10 20:14:58 +01:00 committed by GitHub
commit b847caa11b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 3009 additions and 688 deletions

View file

@ -54,7 +54,12 @@ namespace librs
return Sha1CheckSum(h);
}
template<>
HashStream& operator<<(HashStream& u,const std::pair<unsigned char *,uint32_t>& p)
{
EVP_DigestUpdate(u.mdctx,p.first,p.second) ;
return u;
}
template<>
HashStream& operator<<(HashStream& u,const std::string& s)
{

View file

@ -0,0 +1,202 @@
/*******************************************************************************
* libretroshare/src/file_sharing: fsclient.cc *
* *
* libretroshare: retroshare core library *
* *
* Copyright 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/>. *
* *
******************************************************************************/
#include "pqi/pqithreadstreamer.h"
#include "retroshare/rspeers.h"
#include "fsclient.h"
#include "pqi/pqifdbin.h"
#include "pqi/pqiproxy.h"
bool FsClient::requestFriends(const std::string& address,uint16_t port,
const std::string& proxy_address,uint16_t proxy_port,
uint32_t reqs,std::map<std::string,bool>& friend_certificates)
{
// send our own certificate to publish and expects response frmo the server , decrypts it and reutnrs friend list
RsFriendServerClientPublishItem *pitem = new RsFriendServerClientPublishItem();
pitem->n_requested_friends = reqs;
std::string pgp_base64_string,pgp_base64_checksum,short_invite;
rsPeers->GetPGPBase64StringAndCheckSum(rsPeers->getGPGOwnId(),pgp_base64_string,pgp_base64_checksum);
if(!rsPeers->getShortInvite(short_invite,RsPeerId(),RetroshareInviteFlags::RADIX_FORMAT | RetroshareInviteFlags::DNS))
{
RsErr() << "Cannot request own short invite! Something's very wrong." ;
return false;
}
pitem->pgp_public_key_b64 = pgp_base64_string;
pitem->short_invite = short_invite;
std::list<RsItem*> response;
sendItem(address,port,proxy_address,proxy_port,pitem,response);
// now decode the response
friend_certificates.clear();
for(auto item:response)
{
// auto *encrypted_response_item = dynamic_cast<RsFriendServerEncryptedServerResponseItem*>(item);
// if(!encrypted_response_item)
// {
// delete item;
// continue;
// }
// For now, also handle unencrypted response items. Will be disabled in production
auto *response_item = dynamic_cast<RsFriendServerServerResponseItem*>(item);
if(response_item)
handleServerResponse(response_item);
delete item;
}
return friend_certificates.size();
}
void FsClient::handleServerResponse(RsFriendServerServerResponseItem *item)
{
std::cerr << "Received a response item from server: " << std::endl;
std::cerr << *item << std::endl;
// for(const auto& it:response_item->friend_invites)
// friend_certificates.insert(it);
}
bool FsClient::sendItem(const std::string& server_address,uint16_t server_port,
const std::string& proxy_address,uint16_t proxy_port,
RsItem *item,std::list<RsItem*>& response)
{
// open a connection
RsDbg() << "Sending item to friend server at \"" << server_address << ":" << server_port << " through proxy " << proxy_address << ":" << proxy_port;
int CreateSocket = 0;
char dataReceived[1024];
struct sockaddr_in ipOfServer;
memset(dataReceived, '0' ,sizeof(dataReceived));
if((CreateSocket = socket(AF_INET, SOCK_STREAM, 0))< 0)
{
printf("Socket not created \n");
return 1;
}
ipOfServer.sin_family = AF_INET;
ipOfServer.sin_port = htons(proxy_port);
ipOfServer.sin_addr.s_addr = inet_addr(proxy_address.c_str());
if(connect(CreateSocket, (struct sockaddr *)&ipOfServer, sizeof(ipOfServer))<0)
{
printf("Connection to proxy failed due to port and ip problems, or proxy is not available\n");
return false;
}
// Now connect to the proxy
int ret=0;
pqiproxyconnection proxy;
proxy.setRemoteAddress(server_address);
proxy.setRemotePort(server_port);
while(1 != (ret = proxy.proxy_negociate_connection(CreateSocket)))
if(ret < 0)
{
RsErr() << "FriendServer client: Connection problem to the proxy!" ;
return false;
}
else
std::this_thread::sleep_for(std::chrono::milliseconds(200));
// Serialise the item and send it.
FsSerializer *fss = new FsSerializer;
RsSerialiser *rss = new RsSerialiser(); // deleted by ~pqistreamer()
rss->addSerialType(fss);
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);
p.start();
uint32_t ss;
p.SendItem(item,ss);
RsDbg() << "Item sent. Waiting for response..." ;
// Now attempt to read and deserialize anything that comes back from that connexion until it gets closed by the server.
while(true)
{
p.tick(); // ticks bio
RsItem *item = GetItem();
#ifdef DEBUG_FSCLIENT
RsDbg() << "Ticking for response...";
#endif
if(item)
{
response.push_back(item);
std::cerr << "Got a response item: " << std::endl;
std::cerr << *item << std::endl;
RsDbg() << "End of transmission. " ;
break;
}
else
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
RsDbg() << " Stopping/killing pqistreamer" ;
p.fullstop();
RsDbg() << " Closing socket." ;
close(CreateSocket);
CreateSocket=0;
RsDbg() << " Exiting loop." ;
return true;
}
bool FsClient::RecvItem(RsItem *item)
{
mIncomingItems.push_back(item);
return true;
}
RsItem *FsClient::GetItem()
{
if(mIncomingItems.empty())
return nullptr;
RsItem *item = mIncomingItems.front();
mIncomingItems.pop_front();
return item;
}

View file

@ -0,0 +1,54 @@
/*******************************************************************************
* libretroshare/src/file_sharing: fsclient.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright 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/>. *
* *
******************************************************************************/
#include <string>
#include "fsitem.h"
#include "pqi/pqi_base.h"
// This class runs a client connection to the friend server. It opens a socket at each connection.
class FsClient: public PQInterface
{
public:
FsClient() :PQInterface(RsPeerId()) {}
bool requestFriends(const std::string& address, uint16_t port,
const std::string &proxy_address, uint16_t proxy_port,
uint32_t reqs, std::map<std::string,bool>& friend_certificates);
protected:
// Implements PQInterface
bool RecvItem(RsItem *item) override;
int SendItem(RsItem *) override { RsErr() << "FsClient::SendItem() called although it should not." ; return 0;}
RsItem *GetItem() override;
private:
bool sendItem(const std::string &server_address, uint16_t server_port,
const std::string &proxy_address, uint16_t proxy_port,
RsItem *item, std::list<RsItem *> &response);
void handleServerResponse(RsFriendServerServerResponseItem *item);
std::list<RsItem*> mIncomingItems;
};

View file

@ -0,0 +1,185 @@
/*******************************************************************************
* libretroshare/src/file_sharing: fsitem.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright 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 "serialiser/rsserial.h"
#include "serialiser/rsserializer.h"
#include "rsitems/rsitem.h"
#include "serialiser/rstlvbinary.h"
#include "rsitems/rsserviceids.h"
#include "rsitems/itempriorities.h"
const uint8_t RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH = 0x01 ;
const uint8_t RS_PKT_SUBTYPE_FS_CLIENT_REMOVE = 0x02 ;
const uint8_t RS_PKT_SUBTYPE_FS_SERVER_RESPONSE = 0x03 ;
const uint8_t RS_PKT_SUBTYPE_FS_SERVER_ENCRYPTED_RESPONSE = 0x04 ;
const uint8_t RS_PKT_SUBTYPE_FS_SERVER_STATUS = 0x05 ;
class RsFriendServerItem: public RsItem
{
public:
RsFriendServerItem(uint8_t item_subtype) : RsItem(RS_PKT_VERSION_SERVICE,RS_SERVICE_TYPE_FRIEND_SERVER,item_subtype)
{
setPriorityLevel(QOS_PRIORITY_DEFAULT) ;
}
virtual ~RsFriendServerItem() {}
virtual void clear() override {}
};
class RsFriendServerClientPublishItem: public RsFriendServerItem
{
public:
RsFriendServerClientPublishItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH) {}
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override
{
RS_SERIAL_PROCESS(n_requested_friends);
RS_SERIAL_PROCESS(short_invite);
RS_SERIAL_PROCESS(pgp_public_key_b64);
}
virtual void clear() override
{
pgp_public_key_b64.clear();
short_invite.clear();
n_requested_friends=0;
}
// specific members for that item
uint32_t n_requested_friends;
std::string short_invite;
std::string pgp_public_key_b64;
};
class RsFriendServerStatusItem: public RsFriendServerItem
{
public:
RsFriendServerStatusItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_SERVER_STATUS) {}
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override
{
RS_SERIAL_PROCESS(status);
}
enum ConnectionStatus: uint8_t
{
UNKNOWN = 0x00,
END_OF_TRANSMISSION = 0x01
};
// specific members for that item
ConnectionStatus status;
};
class RsFriendServerClientRemoveItem: public RsFriendServerItem
{
public:
RsFriendServerClientRemoveItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_CLIENT_REMOVE) {}
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx)
{
RS_SERIAL_PROCESS(peer_id);
RS_SERIAL_PROCESS(nonce);
}
// Peer ID for the peer to remove.
RsPeerId peer_id;
// Nonce that was returned by the server after the last client request. Should match in order to proceed. This prevents
// a malicious actor from removing peers from the server. Since the nonce is sent through Tor tunnels, it cannot be known by
// anyone else than the client.
uint64_t nonce;
};
class RsFriendServerEncryptedServerResponseItem: public RsFriendServerItem
{
public:
RsFriendServerEncryptedServerResponseItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_SERVER_ENCRYPTED_RESPONSE) {}
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override
{
RsTypeSerializer::RawMemoryWrapper prox(bin_data, bin_len);
RsTypeSerializer::serial_process(j, ctx, prox, "data");
}
virtual void clear() override
{
free(bin_data);
bin_len = 0;
bin_data = nullptr;
}
//
void *bin_data;
uint32_t bin_len;
};
class RsFriendServerServerResponseItem: public RsFriendServerItem
{
public:
RsFriendServerServerResponseItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_SERVER_RESPONSE) {}
void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override
{
RS_SERIAL_PROCESS(nonce);
RS_SERIAL_PROCESS(friend_invites);
}
virtual void clear() override
{
friend_invites.clear();
nonce = 0;
}
// specific members for that item
uint64_t nonce;
std::map<std::string,bool> friend_invites;
};
struct FsSerializer : RsServiceSerializer
{
FsSerializer(RsSerializationFlags flags = RsSerializationFlags::NONE): RsServiceSerializer(RS_SERVICE_TYPE_FRIEND_SERVER, flags) {}
virtual RsItem *create_item(uint16_t service_id,uint8_t item_sub_id) const
{
if(service_id != static_cast<uint16_t>(RsServiceType::FRIEND_SERVER))
return nullptr;
switch(item_sub_id)
{
case RS_PKT_SUBTYPE_FS_CLIENT_REMOVE: return new RsFriendServerClientRemoveItem();
case RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH: return new RsFriendServerClientPublishItem();
case RS_PKT_SUBTYPE_FS_SERVER_RESPONSE: return new RsFriendServerServerResponseItem();
case RS_PKT_SUBTYPE_FS_SERVER_STATUS: return new RsFriendServerStatusItem();
case RS_PKT_SUBTYPE_FS_SERVER_ENCRYPTED_RESPONSE: return new RsFriendServerEncryptedServerResponseItem();
default:
RsErr() << "Unknown subitem type " << item_sub_id << " in FsSerialiser" ;
return nullptr;
}
}
};

View file

@ -0,0 +1,123 @@
#include <cmath>
#include "fsmanager.h"
#include "fsclient.h"
RsFriendServer *rsFriendServer = nullptr;
static const rstime_t MIN_DELAY_BETWEEN_FS_REQUESTS = 30;
static const rstime_t MAX_DELAY_BETWEEN_FS_REQUESTS = 3600;
static const uint32_t DEFAULT_FRIENDS_TO_REQUEST = 10;
static const std::string DEFAULT_PROXY_ADDRESS = "127.0.0.1";
static const uint16_t DEFAULT_FRIEND_SERVER_PORT = 2017;
static const uint16_t DEFAULT_PROXY_PORT = 9050;
FriendServerManager::FriendServerManager()
{
mLastFriendReqestCampain = 0;
mFriendsToRequest = DEFAULT_FRIENDS_TO_REQUEST;
mProxyAddress = DEFAULT_PROXY_ADDRESS;
mProxyPort = DEFAULT_PROXY_PORT;
mServerPort = DEFAULT_FRIEND_SERVER_PORT;
}
void FriendServerManager::startServer()
{
if(!isRunning())
{
std::cerr << "Starting Friend Server Manager." << std::endl;
RsTickingThread::start() ;
}
}
void FriendServerManager::stopServer()
{
if(isRunning() && !shouldStop())
{
std::cerr << "Stopping Friend Server Manager." << std::endl;
RsTickingThread::askForStop() ;
}
}
void FriendServerManager::checkServerAddress_async(const std::string& addr,uint16_t, const std::function<void (const std::string& address,bool result_status)>& callback)
{
#warning TODO
std::this_thread::sleep_for(std::chrono::seconds(1));
callback(addr,true);
}
void FriendServerManager::setServerAddress(const std::string& addr,uint16_t port)
{
mServerAddress = addr;
mServerPort = port;
}
void FriendServerManager::setProxyAddress(const std::string& addr,uint16_t port)
{
mProxyAddress = addr;
mProxyPort = port;
}
void FriendServerManager::setFriendsToRequest(uint32_t n)
{
mFriendsToRequest = n;
}
void FriendServerManager::threadTick()
{
std::cerr << "Ticking FriendServerManager..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
if(mServerAddress.empty())
{
RsErr() << "No friend server address has been setup. This is probably a bug.";
return;
}
// Check for requests. Compute how much to wait based on how many friends we have already
std::vector<RsPgpId> friends;
rsPeers->getPgpFriendList(friends);
// log-scale interpolation of the delay between two requests.
if(mFriendsToRequest == 0 || mFriendsToRequest < friends.size())
{
RsErr() << "No friends to request! This is unexpected. Returning." << std::endl;
return;
}
// This formula makes RS wait much longuer between two requests to the server when the number of friends is close the
// wanted number
// Delay for 0 friends: 30 secs.
// Delay for 1 friends: 30 secs.
// Delay for 2 friends: 32 secs.
// Delay for 3 friends: 35 secs.
// Delay for 4 friends: 44 secs.
// Delay for 5 friends: 66 secs.
// Delay for 6 friends: 121 secs.
// Delay for 7 friends: 258 secs.
// Delay for 8 friends: 603 secs.
// Delay for 9 friends: 1466 secs.
RsDbg() << friends.size() << " friends already, " << mFriendsToRequest << " friends to request";
double s = (friends.size() < mFriendsToRequest)? ( (mFriendsToRequest - friends.size())/(double)mFriendsToRequest) : 1.0;
rstime_t delay_for_request = MIN_DELAY_BETWEEN_FS_REQUESTS + (int)floor(exp(-1*s + log(MAX_DELAY_BETWEEN_FS_REQUESTS)*(1.0-s)));
std::cerr << "Delay for " << friends.size() << " friends: " << delay_for_request << " secs." << std::endl;
rstime_t now = time(nullptr);
if(mLastFriendReqestCampain + delay_for_request < now)
{
mLastFriendReqestCampain = now;
std::cerr << "Requesting new friends to friend server..." << std::endl;
std::map<std::string,bool> friend_certificates;
FsClient().requestFriends(mServerAddress,mServerPort,mProxyAddress,mProxyPort,mFriendsToRequest,friend_certificates); // blocking call
std::cerr << "Got the following list of friend certificates:" << std::endl;
for(const auto& it:friend_certificates)
std::cerr << it.first << " : " << it.second << std::endl;
}
}

View file

@ -0,0 +1,51 @@
#include <map>
#include "util/rsthreads.h"
#include "retroshare/rsfriendserver.h"
#include "retroshare/rspeers.h"
struct FriendServerPeerInfo
{
enum FriendServerPeerStatus: uint8_t
{
UNKNOWN = 0x00,
LOCALLY_ACCEPTED = 0x01,
HAS_ACCEPTED_ME = 0x02,
ALREADY_CONNECTED = 0x03
};
uint32_t status ;
rstime_t received_TS;
};
class FriendServerManager: public RsFriendServer, public RsTickingThread
{
public:
FriendServerManager();
virtual void startServer() override ;
virtual void stopServer() override ;
virtual void checkServerAddress_async(const std::string& addr,uint16_t, const std::function<void (const std::string& address,bool result_status)>& callback) override ;
virtual void setServerAddress(const std::string&,uint16_t) override ;
virtual void setProxyAddress(const std::string&,uint16_t) override ;
virtual void setFriendsToRequest(uint32_t) override ;
virtual uint32_t friendsToRequest() override { return mFriendsToRequest ; }
virtual uint16_t friendsServerPort() override { return mServerPort ; }
virtual std::string friendsServerAddress() override { return mServerAddress ; }
protected:
virtual void threadTick() override;
private:
uint32_t mFriendsToRequest;
rstime_t mLastFriendReqestCampain;
// encode the current list of friends obtained through the friendserver and their status
std::map<RsPeerId, FriendServerPeerInfo> mPeers;
std::string mServerAddress ;
uint16_t mServerPort;
std::string mProxyAddress ;
uint16_t mProxyPort;
};

View file

@ -391,6 +391,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 \
@ -559,6 +560,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 \
@ -825,6 +827,22 @@ wikipoos {
rsitems/rswikiitems.cc \
}
# Friend server
rs_efs {
DEFINES *= RS_EMBEDED_FRIEND_SERVER
HEADERS += friend_server/fsclient.h \
friend_server/fsitem.h \
friend_server/fsmanager.h \
retroshare/rsfriendserver.h
SOURCES += friend_server/fsclient.cc \
friend_server/fsmanager.cc
}
# The Wire
gxsthewire {
DEFINES *= RS_USE_WIRE

View file

@ -1642,7 +1642,10 @@ bool OpenPGPSDKHandler::locked_syncPublicKeyring()
#else
if(-1 == stat64(_pubring_path.c_str(), &buf))
#endif
{
RsErr() << "OpenPGPSDKHandler::syncDatabase(): can't stat file " << _pubring_path << ". Can't sync public keyring." ;
buf.st_mtime = 0;
}
if(_pubring_last_update_time < buf.st_mtime)
{

View file

@ -357,12 +357,13 @@ bool PGPHandler::locked_syncTrustDatabase()
librs::util::ConvertUtf8ToUtf16(_trustdb_path, wfullname);
if(-1 == _wstati64(wfullname.c_str(), &buf))
#else
if(-1 == stat64(_trustdb_path.c_str(), &buf))
if(-1 == stat64(_trustdb_path.c_str(), &buf))
#endif
{
RsErr() << "PGPHandler::syncDatabase(): can't stat file " << _trustdb_path << ". Will force write it." ;
_trustdb_changed = true ; // we force write of trust database if it does not exist.
}
{
RsErr() << "PGPHandler::syncDatabase(): can't stat file " << _trustdb_path << ". Will force write it." ;
_trustdb_changed = true ; // we force write of trust database if it does not exist.
buf.st_mtime = 0;
}
if(_trustdb_last_update_time < buf.st_mtime)
{

View file

@ -21,6 +21,7 @@
*******************************************************************************/
#include <stdint.h>
#include <util/radix64.h>
#include <crypto/hashstream.h>
#include "pgpkeyutil.h"
#include <iostream>
@ -181,6 +182,59 @@ uint32_t PGPKeyManagement::compute24bitsCRC(unsigned char *octets, size_t len)
return crc & 0xFFFFFFL;
}
bool PGPKeyManagement::parsePGPPublicKey(const unsigned char *keydata, size_t keylen, PGPKeyInfo& info)
{
#ifdef DEBUG_PGPUTIL
std::cerr << "Total size: " << keylen << std::endl;
#endif
unsigned char *data = (unsigned char*)keydata;
uint8_t packet_tag;
uint32_t packet_length ;
PGPKeyParser::read_packetHeader(data,packet_tag,packet_length) ;
#ifdef DEBUG_PGPUTIL
std::cerr << "Packet tag : " << (int)packet_tag << ", length=" << packet_length << std::endl;
#endif
if(packet_tag != PGPKeyParser::PGP_PACKET_TAG_PUBLIC_KEY)
{
std::cerr << "(EE) Parsing error in PGP public key. Expected a public key tag (6). Found " << (int)packet_tag << " instead." << std::endl;
return false;
}
librs::crypto::HashStream H(librs::crypto::HashStream::SHA1);
H << (uint8_t)0x99; // RFC_4880
std::cerr << "Packet length = " << packet_length << std::endl;
H << (uint8_t)(packet_length >> 8);
H << (uint8_t)(packet_length);
H << std::make_pair(data,packet_length) ;
auto hash = H.hash();
memcpy(info.fingerprint, hash.toByteArray(),hash.SIZE_IN_BYTES);
data += packet_length;
// Read user ID.
PGPKeyParser::read_packetHeader(data,packet_tag,packet_length) ;
if(packet_tag != PGPKeyParser::PGP_PACKET_TAG_USER_ID)
{
std::cerr << "(EE) Parsing error in PGP public key. Expected a user ID key tag (13). Found " << (int)packet_tag << " instead." << std::endl;
return false;
}
info.user_id.clear();
for(uint32_t i=0;i<packet_length;++i)
info.user_id += (char)(data[i]);
return true ;
}
bool PGPKeyManagement::parseSignature(const unsigned char *signature, size_t sign_len, PGPSignatureInfo& info)
{
unsigned char *data = (unsigned char *)signature ;

View file

@ -81,6 +81,16 @@ public:
uint8_t hash_algorithm ;
};
class PGPKeyInfo
{
public:
PGPKeyInfo() {}
std::string user_id;
unsigned char fingerprint[20];
};
// This class handles GPG keys. For now we only clean them from signatures, but
// in the future, we might cache them to avoid unnecessary calls to gpgme.
//
@ -107,6 +117,8 @@ class PGPKeyManagement
static uint32_t compute24bitsCRC(unsigned char *data,size_t len) ;
static bool parseSignature(const unsigned char *signature, size_t sign_len, PGPSignatureInfo& info) ;
static bool parsePGPPublicKey(const unsigned char *keydata, size_t keylen, PGPKeyInfo& info);
};
// This class handles the parsing of PGP packet headers under various (old and new) formats.
@ -126,7 +138,7 @@ class PGPKeyParser
static uint64_t read_KeyID(unsigned char *& data) ;
static uint32_t read_125Size(unsigned char *& data) ;
static uint32_t read_partialBodyLength(unsigned char *& data) ;
static void read_packetHeader(unsigned char *& data,uint8_t& packet_tag,uint32_t& packet_length) ;
static void read_packetHeader(unsigned char *&data, uint8_t& packet_tag, uint32_t& packet_length) ;
// These functions write, and indicate how many bytes where written.
//

View file

@ -28,6 +28,7 @@
#include <retroshare/rspeers.h>
#include <util/radix64.h>
#include <pgp/pgpkeyutil.h>
#include <pgp/pgphandler.h>
#include "rscertificate.h"
#include "util/rsstring.h"
#include "util/stacktrace.h"
@ -619,6 +620,140 @@ bool RsCertificate::cleanRadix64(const std::string& instr,std::string& str,uint3
return true ;
}
bool RsCertificate::decodeRadix64ShortInvite(const std::string& rsInvite, RsPeerDetails& details, uint32_t& err_code)
{
err_code = 0;
std::vector<uint8_t> bf = Radix64::decode(rsInvite);
size_t size = bf.size();
unsigned char* buf = bf.data();
size_t total_s = 0;
bool CRC_ok = false ; // not checked yet
while(total_s < size)
{
RsShortInviteFieldType ptag = RsShortInviteFieldType(buf[0]);
buf = &buf[1];
unsigned char *buf2 = buf;
uint32_t s = 0;
try { s = PGPKeyParser::read_125Size(buf); }
catch (...)
{
err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR;
return false;
}
total_s += 1 + ( reinterpret_cast<size_t>(buf) - reinterpret_cast<size_t>(buf2) );
if(total_s > size)
{
err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR;
return false;
}
Dbg3() << __PRETTY_FUNCTION__ << " Read ptag: "
<< static_cast<uint32_t>(ptag)
<< ", size " << s << ", total_s = " << total_s
<< ", expected total = " << size << std::endl;
switch(ptag)
{
case RsShortInviteFieldType::SSL_ID:
details.id = RsPeerId::fromBufferUnsafe(buf) ;
break;
case RsShortInviteFieldType::PEER_NAME:
details.name = std::string((char*)buf,s);
break;
case RsShortInviteFieldType::PGP_FINGERPRINT:
details.fpr = RsPgpFingerprint::fromBufferUnsafe(buf);
details.gpg_id = PGPHandler::pgpIdFromFingerprint(details.fpr);
break;
case RsShortInviteFieldType::LOCATOR:
{
std::string locatorStr((char*)buf,s);
details.ipAddressList.push_back(locatorStr);
}
break;
case RsShortInviteFieldType::DNS_LOCATOR:
details.extPort = (((int)buf[0]) << 8) + buf[1];
details.dyndns = std::string((char*)&buf[2],s-2);
break;
case RsShortInviteFieldType::LOC4_LOCATOR:
{
uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
sockaddr_in tLocalAddr;
tLocalAddr.sin_addr.s_addr = t4Addr;
details.localAddr = rs_inet_ntoa(tLocalAddr.sin_addr);
details.localPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5];
}
break;
case RsShortInviteFieldType::EXT4_LOCATOR:
{
uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
sockaddr_in tExtAddr;
tExtAddr.sin_addr.s_addr = t4Addr;
details.extAddr = rs_inet_ntoa(tExtAddr.sin_addr);
details.extPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5];
}
break;
case RsShortInviteFieldType::HIDDEN_LOCATOR:
details.hiddenType = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
details.hiddenNodePort = (((uint32_t)buf[4]) << 8)+ (uint32_t)buf[5];
details.isHiddenNode = true;
details.hiddenNodeAddress = std::string((char*)&buf[6],s-6);
break;
case RsShortInviteFieldType::CHECKSUM:
{
if(s != 3 || total_s+3 != size) // make sure the checksum is the last section
{
err_code = CERTIFICATE_PARSING_ERROR_INVALID_CHECKSUM_SECTION;
return false;
}
uint32_t computed_crc = PGPKeyManagement::compute24bitsCRC(bf.data(),size-5);
uint32_t certificate_crc = static_cast<uint32_t>( buf[0] + (buf[1] << 8) + (buf[2] << 16) );
if(computed_crc != certificate_crc)
{
err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR;
return false;
}
CRC_ok = true;
break;
}
}
buf = &buf[s];
total_s += s;
}
if(details.id.isNull())
{
err_code = CERTIFICATE_PARSING_ERROR_MISSING_LOCATION_ID;
return false;
}
if(!CRC_ok)
{
err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR;
return false;
}
return true;
}

View file

@ -36,6 +36,21 @@ struct RsPeerDetails;
class RsCertificate
{
public:
enum class RsShortInviteFieldType : uint8_t
{
SSL_ID = 0x00,
PEER_NAME = 0x01,
LOCATOR = 0x02,
PGP_FINGERPRINT = 0x03,
CHECKSUM = 0x04,
/* The following will be deprecated, and ported to LOCATOR when generic transport layer will be implemented */
HIDDEN_LOCATOR = 0x90,
DNS_LOCATOR = 0x91,
EXT4_LOCATOR = 0x92, // external IPv4 address
LOC4_LOCATOR = 0x93 // local IPv4 address
};
typedef enum { RS_CERTIFICATE_OLD_FORMAT, RS_CERTIFICATE_RADIX, RS_CERTIFICATE_SHORT_RADIX } Format;
/**
@ -64,6 +79,8 @@ public:
~RsCertificate();
static bool decodeRadix64ShortInvite(const std::string& short_invite_b64,RsPeerDetails& det,uint32_t& error_code);
/// Convert to certificate radix string
std::string toStdString() const;

View file

@ -280,7 +280,8 @@ public:
* Sends data to a prescribed location (implementation dependent)
*@param data what will be sent
*@param len the size of data pointed to in memory
*/
*@returns total number of bytes actually sent
*/
virtual int senddata(void *data, int len) = 0;
/**

View file

@ -236,6 +236,7 @@ int RsFdBinInterface::readline(void *data, int len)
return 0;
}
int RsFdBinInterface::readdata(void *data, int len)
{
// read incoming bytes in the buffer

View file

@ -0,0 +1,469 @@
#include "util/rsdebug.h"
#include "util/rsnet.h"
#include "pqi/pqiproxy.h"
//#define PROXY_DEBUG 1
int pqiproxyconnection::proxy_negociate_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.
if(ret < 1)
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;
}
if(ret < 0)
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,72 @@
/*******************************************************************************
* 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
};
pqiproxyconnection() : mProxyState(PROXY_STATE_INIT) {}
/*!
* \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_negociate_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();
@ -84,499 +78,31 @@ int pqisslproxy::Initiate_Connection()
/********* VERY DIFFERENT **********/
int pqisslproxy::Basic_Connection_Complete()
{
rslog(RSL_DEBUG_BASIC, pqisslproxyzone,
"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;
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)
if (CheckConnectionTimeout())
{
#ifdef PROXY_DEBUG
std::cerr << "pqisslproxy::Proxy_Method_Response() recv error";
std::cerr << std::endl;
#endif
// calls reset.
return -1;
}
// does it make sense?
if (method_response[0] != 0x05)
{
int ret;
// 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(proxyConnectionState() == PROXY_STATE_INIT && 1!=(ret=pqissl::Basic_Connection_Complete()))
return ret; // basic connection not complete.
if (method_response[1] != 0x00)
{
ret = proxy_negociate_connection(sockfd);
#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;
if(ret < 0)
reset_locked();
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)
rs_sprintf(out, "pqisslproxy::connect_parameter() Peer: %s DOMAIN_ADDRESS: %s", PeerId().toStdString().c_str(), value.c_str());
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

View file

@ -357,6 +357,7 @@ int pqistreamer::status()
// this method is overloaded by pqiqosstreamer
void pqistreamer::locked_storeInOutputQueue(void *ptr,int,int)
{
RsDbg() << "Storing packet " << std::hex << ptr << std::dec << " in outqueue.";
mOutPkts.push_back(ptr);
}
@ -521,7 +522,7 @@ int pqistreamer::handleoutgoing_locked()
{
/* if we are not active - clear anything in the queues. */
locked_clear_out_queue() ;
#ifdef DEBUG_PACKET_SLICING
#ifdef DEBUG_PACKET_SLICING
std::cerr << "(II) Switching off packet slicing." << std::endl;
#endif
mAcceptsPacketSlicing = false ;
@ -683,7 +684,7 @@ int pqistreamer::handleoutgoing_locked()
outSentBytes_locked(mPkt_wpending_size); // this is the only time where we know exactly what was sent.
#ifdef DEBUG_TRANSFERS
std::cerr << "pqistreamer::handleoutgoing_locked() Sent Packet len: " << mPkt_wpending_size << " @ " << RsUtil::AccurateTimeString();
std::cerr << "pqistreamer::handleoutgoing_locked() Sent Packet len: " << mPkt_wpending_size << " @ " << getCurrentTS();
std::cerr << std::endl;
#endif
@ -693,7 +694,7 @@ int pqistreamer::handleoutgoing_locked()
mPkt_wpending = NULL;
mPkt_wpending_size = 0 ;
sent = true;
sent = true;
}
}
#ifdef DEBUG_PQISTREAMER
@ -802,11 +803,14 @@ start_packet_read:
if(!memcmp(block,PACKET_SLICING_PROBE_BYTES,8))
{
mAcceptsPacketSlicing = !DISABLE_PACKET_SLICING;
mAcceptsPacketSlicing = !DISABLE_PACKET_SLICING;
#ifdef DEBUG_PACKET_SLICING
std::cerr << "(II) Enabling packet slicing!" << std::endl;
#endif
}
mReading_state = reading_state_initial ; // restart at state 1.
mFailed_read_attempts = 0 ;
return 0;
}
}
continue_packet:
{
@ -1430,8 +1434,12 @@ void *pqistreamer::locked_pop_out_data(uint32_t /*max_slice_size*/, uint32_t &si
{
res = *(mOutPkts.begin());
mOutPkts.pop_front();
// In pqistreamer, we do not split outgoing packets. For now only pqiQoSStreamer supports packet slicing.
size = getRsItemSize(res);
#ifdef DEBUG_TRANSFERS
std::cerr << "pqistreamer::locked_pop_out_data() getting next pkt from mOutPkts queue";
std::cerr << "pqistreamer::locked_pop_out_data() getting next pkt " << std::hex << res << std::dec << " from mOutPkts queue";
std::cerr << std::endl;
#endif
}

View file

@ -31,8 +31,8 @@ public:
pqithreadstreamer(PQInterface *parent, RsSerialiser *rss, const RsPeerId& peerid, BinInterface *bio_in, int bio_flagsin);
// from pqistreamer
virtual bool RecvItem(RsItem *item);
virtual int tick();
virtual bool RecvItem(RsItem *item) override;
virtual int tick() override;
protected:
void threadTick() override; /// @see RsTickingThread

View file

@ -0,0 +1,39 @@
#include <functional>
#include <thread>
#include "util/rstime.h"
// The Friend Server component of Retroshare automatically adds/removes some friends so that the
//
// The current strategy is:
//
// - if total nb of friends < S
// request new friends to the FS
// - if total nb of friends >= S
// do not request anymore (and unpublish the key), but keep the friends already here
//
// Possible states:
// - not started
// - maintain friend list
// - actively request friends
//
// The friend server internally keeps track of which friends have been added using the friend server.
// It's important to keep the ones that are already connected because they may count on us.
// Friends supplied by the FS who never connected for a few days should be removed automatically.
class RsFriendServer
{
public:
virtual void startServer() =0;
virtual void stopServer() =0;
virtual void checkServerAddress_async(const std::string& addr,uint16_t, const std::function<void (const std::string& address,bool result_status)>& callback) =0;
virtual void setServerAddress(const std::string&,uint16_t) =0;
virtual void setProxyAddress(const std::string&,uint16_t) =0;
virtual void setFriendsToRequest(uint32_t) =0;
virtual uint32_t friendsToRequest() =0;
virtual uint16_t friendsServerPort() =0;
virtual std::string friendsServerAddress() =0;
};
extern RsFriendServer *rsFriendServer;

View file

@ -168,6 +168,15 @@ struct t_RsGenericIdType
return ret;
}
inline Id_t operator^ (const Id_t& fp) const
{
Id_t ret;
for(uint32_t i=0; i < ID_SIZE_IN_BYTES; ++i)
ret.bytes[i] = bytes[i] ^ fp.bytes[i];
return ret;
}
inline bool isNull() const
{
for(uint32_t i=0; i < SIZE_IN_BYTES; ++i)

View file

@ -54,7 +54,8 @@ enum class RsServiceType : uint16_t
BANLIST = 0x0101,
STATUS = 0x0102,
NXS = 0x0200,
FRIEND_SERVER = 0x0103,
NXS = 0x0200,
GXSID = 0x0211,
PHOTO = 0x0212,
WIKI = 0x0213,
@ -115,6 +116,8 @@ RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_DISTANT_CHAT =
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_GXS_TUNNEL = 0x0028;
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_BANLIST = 0x0101;
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_STATUS = 0x0102;
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_FRIEND_SERVER = 0x0103;
/// Rs Network Exchange Service
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_NXS = 0x0200;
RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_GXSID = 0x0211;

View file

@ -48,6 +48,7 @@
#include "pqi/authssl.h"
typedef RsCertificate::RsShortInviteFieldType RsShortInviteFieldType; // locally in this file to avoid renaming everything.
RsPeers *rsPeers = NULL;
@ -1162,22 +1163,6 @@ bool p3Peers::GetPGPBase64StringAndCheckSum(
return true;
}
enum class RsShortInviteFieldType : uint8_t
{
SSL_ID = 0x00,
PEER_NAME = 0x01,
LOCATOR = 0x02,
PGP_FINGERPRINT = 0x03,
CHECKSUM = 0x04,
/* The following will be deprecated, and ported to LOCATOR when generic
* trasport layer will be implemented */
HIDDEN_LOCATOR = 0x90,
DNS_LOCATOR = 0x91,
EXT4_LOCATOR = 0x92, // external IPv4 address
LOC4_LOCATOR = 0x93 // local IPv4 address
};
static void addPacketHeader(RsShortInviteFieldType ptag, size_t size, unsigned char *& buf, uint32_t& offset, uint32_t& buf_size)
{
// Check that the buffer has sufficient size. If not, increase it.
@ -1373,136 +1358,23 @@ bool p3Peers::getShortInvite(std::string& invite, const RsPeerId& _sslId, Retros
bool p3Peers::parseShortInvite(const std::string& inviteStrUrl, RsPeerDetails& details, uint32_t &err_code )
{
if(inviteStrUrl.empty())
{
RsErr() << __PRETTY_FUNCTION__ << " can't parse empty invite"
<< std::endl;
return false;
}
std::string rsInvite = inviteStrUrl;
if(inviteStrUrl.empty())
{
RsErr() << __PRETTY_FUNCTION__ << " can't parse empty invite"
<< std::endl;
return false;
}
std::string rsInvite = inviteStrUrl;
RsUrl inviteUrl(inviteStrUrl);
RsUrl inviteUrl(inviteStrUrl);
if(inviteUrl.hasQueryK("rsInvite"))
rsInvite = *inviteUrl.getQueryV("rsInvite");
if(inviteUrl.hasQueryK("rsInvite"))
rsInvite = *inviteUrl.getQueryV("rsInvite");
std::vector<uint8_t> bf = Radix64::decode(rsInvite);
size_t size = bf.size();
if(!RsCertificate::decodeRadix64ShortInvite(rsInvite, details, err_code))
return false;
unsigned char* buf = bf.data();
size_t total_s = 0;
bool CRC_ok = false ; // not checked yet
while(total_s < size)
{
RsShortInviteFieldType ptag = RsShortInviteFieldType(buf[0]);
buf = &buf[1];
unsigned char *buf2 = buf;
uint32_t s = 0;
try { s = PGPKeyParser::read_125Size(buf); }
catch (...)
{
err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR;
return false;
}
total_s += 1 + ( reinterpret_cast<size_t>(buf) - reinterpret_cast<size_t>(buf2) );
if(total_s > size)
{
err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR;
return false;
}
Dbg3() << __PRETTY_FUNCTION__ << " Read ptag: "
<< static_cast<uint32_t>(ptag)
<< ", size " << s << ", total_s = " << total_s
<< ", expected total = " << size << std::endl;
switch(ptag)
{
case RsShortInviteFieldType::SSL_ID:
details.id = RsPeerId::fromBufferUnsafe(buf) ;
break;
case RsShortInviteFieldType::PEER_NAME:
details.name = std::string((char*)buf,s);
break;
case RsShortInviteFieldType::PGP_FINGERPRINT:
details.fpr = RsPgpFingerprint::fromBufferUnsafe(buf);
details.gpg_id = PGPHandler::pgpIdFromFingerprint(details.fpr);
break;
case RsShortInviteFieldType::LOCATOR:
{
std::string locatorStr((char*)buf,s);
details.ipAddressList.push_back(locatorStr);
}
break;
case RsShortInviteFieldType::DNS_LOCATOR:
details.extPort = (((int)buf[0]) << 8) + buf[1];
details.dyndns = std::string((char*)&buf[2],s-2);
break;
case RsShortInviteFieldType::LOC4_LOCATOR:
{
uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
sockaddr_in tLocalAddr;
tLocalAddr.sin_addr.s_addr = t4Addr;
details.localAddr = rs_inet_ntoa(tLocalAddr.sin_addr);
details.localPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5];
}
break;
case RsShortInviteFieldType::EXT4_LOCATOR:
{
uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
sockaddr_in tExtAddr;
tExtAddr.sin_addr.s_addr = t4Addr;
details.extAddr = rs_inet_ntoa(tExtAddr.sin_addr);
details.extPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5];
}
break;
case RsShortInviteFieldType::HIDDEN_LOCATOR:
details.hiddenType = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
details.hiddenNodePort = (((uint32_t)buf[4]) << 8)+ (uint32_t)buf[5];
details.isHiddenNode = true;
details.hiddenNodeAddress = std::string((char*)&buf[6],s-6);
break;
case RsShortInviteFieldType::CHECKSUM:
{
if(s != 3 || total_s+3 != size) // make sure the checksum is the last section
{
err_code = CERTIFICATE_PARSING_ERROR_INVALID_CHECKSUM_SECTION;
return false;
}
uint32_t computed_crc = PGPKeyManagement::compute24bitsCRC(bf.data(),size-5);
uint32_t certificate_crc = static_cast<uint32_t>( buf[0] + (buf[1] << 8) + (buf[2] << 16) );
if(computed_crc != certificate_crc)
{
err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR;
return false;
}
CRC_ok = true;
break;
}
}
buf = &buf[s];
total_s += s;
}
// now check if the PGP key is available. If so, add it in the PeerDetails:
// Also check if the PGP key is available. If so, add it in the PeerDetails:
RsPeerDetails pgp_det ;
if(getGPGDetails(PGPHandler::pgpIdFromFingerprint(details.fpr),pgp_det) && pgp_det.fpr == details.fpr)
@ -1519,23 +1391,13 @@ bool p3Peers::parseShortInvite(const std::string& inviteStrUrl, RsPeerDetails& d
else
details.skip_pgp_signature_validation = true;
if(!CRC_ok)
{
err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR;
return false;
}
if(details.gpg_id.isNull())
{
err_code = CERTIFICATE_PARSING_ERROR_MISSING_PGP_FINGERPRINT;
return false;
}
if(details.id.isNull())
{
err_code = CERTIFICATE_PARSING_ERROR_MISSING_LOCATION_ID;
return false;
}
err_code = CERTIFICATE_PARSING_ERROR_NO_ERROR;
return true;
err_code = CERTIFICATE_PARSING_ERROR_NO_ERROR;
return true;
}
bool p3Peers::acceptInvite( const std::string& invite,

View file

@ -52,6 +52,10 @@
#include "rsserver/rsloginhandler.h"
#include "rsserver/rsaccounts.h"
#ifdef RS_EMBEDED_FRIEND_SERVER
#include "friend_server/fsmanager.h"
#endif
#include <list>
#include <string>
@ -1175,6 +1179,11 @@ int RsServer::StartupRetroShare()
serviceCtrl->setServiceServer(pqih) ;
#ifdef RS_EMBEDED_FRIEND_SERVER
// setup friend server
rsFriendServer = new FriendServerManager();
#endif
/****** New Ft Server **** !!! */
ftServer *ftserver = new ftServer(mPeerMgr, serviceCtrl);
ftserver->setConfigDirectory(RsAccounts::AccountDirectory());
@ -1936,6 +1945,12 @@ int RsServer::StartupRetroShare()
std::string RsInit::executablePath()
{
if(rsInitConfig->mainExecutablePath.empty())
{
RsErr() << "Main executable path not set! Plz call RsInit::InitRetroShare(conf) with conf.main_executable_path = argv[0]";
assert(false);
}
return rsInitConfig->mainExecutablePath;
}
bool RsInit::startAutoTor()

View file

@ -142,6 +142,8 @@ std::string TorManager::torDataDirectory() const
void TorManager::setTorDataDirectory(const std::string &path)
{
assert(RsDirUtil::checkCreateDirectory(std::string(path)));
d->dataDir = path;
if (!d->dataDir.empty() && !ByteArray(d->dataDir).endsWith('/'))