clean line trailing spaces and tabs

Signed-off-by: R4SAS <r4sas@i2pmail.org>
This commit is contained in:
R4SAS 2021-11-27 23:30:35 +03:00
parent 94661f697b
commit edc0162163
No known key found for this signature in database
GPG Key ID: 66F6C87B98EBCFE2
66 changed files with 998 additions and 999 deletions

View File

@ -395,8 +395,8 @@ namespace client
auto it1 = m_RouterInfoHandlers.find (it->first); auto it1 = m_RouterInfoHandlers.find (it->first);
if (it1 != m_RouterInfoHandlers.end ()) if (it1 != m_RouterInfoHandlers.end ())
{ {
if (!first) results << ","; if (!first) results << ",";
else first = false; else first = false;
(this->*(it1->second))(results); (this->*(it1->second))(results);
} }
else else

View File

@ -225,7 +225,7 @@ namespace transport
} }
std::string strType (GetProto (address)), strPort (std::to_string (address->port)); std::string strType (GetProto (address)), strPort (std::to_string (address->port));
int err = UPNPCOMMAND_SUCCESS; int err = UPNPCOMMAND_SUCCESS;
err = CheckMapping (strPort.c_str (), strType.c_str ()); err = CheckMapping (strPort.c_str (), strType.c_str ());
if (err == UPNPCOMMAND_SUCCESS) if (err == UPNPCOMMAND_SUCCESS)
{ {

View File

@ -272,19 +272,19 @@ namespace data
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
publicKeyLength = BlindECDSA (m_SigType, priv, seed, BlindEncodedPrivateKeyECDSA, blindedPriv, blindedPub); publicKeyLength = BlindECDSA (m_SigType, priv, seed, BlindEncodedPrivateKeyECDSA, blindedPriv, blindedPub);
break; break;
case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
i2p::crypto::GetEd25519 ()->BlindPrivateKey (priv, seed, blindedPriv, blindedPub); i2p::crypto::GetEd25519 ()->BlindPrivateKey (priv, seed, blindedPriv, blindedPub);
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
break; break;
case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
{ {
uint8_t exp[64]; uint8_t exp[64];
i2p::crypto::Ed25519::ExpandPrivateKey (priv, exp); i2p::crypto::Ed25519::ExpandPrivateKey (priv, exp);
i2p::crypto::GetEd25519 ()->BlindPrivateKey (exp, seed, blindedPriv, blindedPub); i2p::crypto::GetEd25519 ()->BlindPrivateKey (exp, seed, blindedPriv, blindedPub);
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
break; break;
} }
default: default:
LogPrint (eLogError, "Blinding: Can't blind signature type ", (int)m_SigType); LogPrint (eLogError, "Blinding: Can't blind signature type ", (int)m_SigType);
} }

View File

@ -389,7 +389,7 @@ namespace crypto
{ {
size_t len = 32; size_t len = 32;
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len); EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
} }
#else #else
memcpy (m_PrivateKey, priv, 32); memcpy (m_PrivateKey, priv, 32);
if (calculatePublic) if (calculatePublic)
@ -440,7 +440,7 @@ namespace crypto
bn2buf (a, encrypted + 1, 256); bn2buf (a, encrypted + 1, 256);
encrypted[257] = 0; encrypted[257] = 0;
bn2buf (b, encrypted + 258, 256); bn2buf (b, encrypted + 258, 256);
BN_free (a); BN_free (a);
BN_CTX_end (ctx); BN_CTX_end (ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
@ -1295,7 +1295,7 @@ namespace crypto
} }
// Noise // Noise
void NoiseSymmetricState::MixHash (const uint8_t * buf, size_t len) void NoiseSymmetricState::MixHash (const uint8_t * buf, size_t len)
{ {
SHA256_CTX ctx; SHA256_CTX ctx;
@ -1311,7 +1311,7 @@ namespace crypto
// new ck is m_CK[0:31], key is m_CK[32:63] // new ck is m_CK[0:31], key is m_CK[32:63]
} }
static void InitNoiseState (NoiseSymmetricState& state, const uint8_t * ck, static void InitNoiseState (NoiseSymmetricState& state, const uint8_t * ck,
const uint8_t * hh, const uint8_t * pub) const uint8_t * hh, const uint8_t * pub)
{ {
// pub is Bob's public static key, hh = SHA256(h) // pub is Bob's public static key, hh = SHA256(h)
@ -1321,19 +1321,19 @@ namespace crypto
SHA256_Update (&ctx, hh, 32); SHA256_Update (&ctx, hh, 32);
SHA256_Update (&ctx, pub, 32); SHA256_Update (&ctx, pub, 32);
SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub)
} }
void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub) void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub)
{ {
static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars
static const uint8_t hh[32] = static const uint8_t hh[32] =
{ {
0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1, 0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1,
0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54 0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54
}; // hh = SHA256(protocol_name || 0) }; // hh = SHA256(protocol_name || 0)
InitNoiseState (state, (const uint8_t *)protocolName, hh, pub); // ck = protocol_name || 0 InitNoiseState (state, (const uint8_t *)protocolName, hh, pub); // ck = protocol_name || 0
} }
void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub) void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub)
{ {
static const uint8_t protocolNameHash[] = static const uint8_t protocolNameHash[] =
@ -1346,8 +1346,8 @@ namespace crypto
0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5,
0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e
}; // SHA256 (protocolNameHash) }; // SHA256 (protocolNameHash)
InitNoiseState (state, protocolNameHash, hh, pub); InitNoiseState (state, protocolNameHash, hh, pub);
} }
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub) void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub)
{ {
@ -1361,9 +1361,9 @@ namespace crypto
0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32, 0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32,
0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c 0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c
}; // SHA256 (protocolNameHash) }; // SHA256 (protocolNameHash)
InitNoiseState (state, protocolNameHash, hh, pub); InitNoiseState (state, protocolNameHash, hh, pub);
} }
// init and terminate // init and terminate
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes; /* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;

View File

@ -95,7 +95,7 @@ namespace crypto
bool IsElligatorIneligible () const { return m_IsElligatorIneligible; } bool IsElligatorIneligible () const { return m_IsElligatorIneligible; }
void SetElligatorIneligible () { m_IsElligatorIneligible = true; } void SetElligatorIneligible () { m_IsElligatorIneligible = true; }
private: private:
uint8_t m_PublicKey[32]; uint8_t m_PublicKey[32];
@ -110,7 +110,7 @@ namespace crypto
}; };
// ElGamal // ElGamal
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted); // 222 bytes data, 514 bytes encrypted void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted); // 222 bytes data, 514 bytes encrypted
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data
void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub); void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub);
@ -317,13 +317,13 @@ namespace crypto
uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/; uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/;
void MixHash (const uint8_t * buf, size_t len); void MixHash (const uint8_t * buf, size_t len);
void MixKey (const uint8_t * sharedSecret); void MixKey (const uint8_t * sharedSecret);
}; };
void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_N (tunnels, router) void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_N (tunnels, router)
void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2) void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2)
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets) void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets)
// init and terminate // init and terminate
void InitCrypto (bool precomputation, bool aesni, bool avx, bool force); void InitCrypto (bool precomputation, bool aesni, bool avx, bool force);
void TerminateCrypto (); void TerminateCrypto ();

View File

@ -29,7 +29,7 @@ namespace crypto
public: public:
virtual ~CryptoKeyDecryptor () {}; virtual ~CryptoKeyDecryptor () {};
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data) = 0; virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data) = 0;
virtual size_t GetPublicKeyLen () const = 0; // we need it to set key in LS2 virtual size_t GetPublicKeyLen () const = 0; // we need it to set key in LS2
}; };

View File

@ -303,7 +303,7 @@ namespace datagram
} }
} }
if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ()) if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ())
{ {
bool found = false; bool found = false;
for (auto& it: m_PendingRoutingSessions) for (auto& it: m_PendingRoutingSessions)
@ -384,7 +384,7 @@ namespace datagram
} }
else else
return nullptr; return nullptr;
auto leaseRouter = i2p::data::netdb.FindRouter (path->remoteLease->tunnelGateway); auto leaseRouter = i2p::data::netdb.FindRouter (path->remoteLease->tunnelGateway);
path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(nullptr, path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(nullptr,
leaseRouter ? leaseRouter->GetCompatibleTransports (false) : (i2p::data::RouterInfo::CompatibleTransports)i2p::data::RouterInfo::eAllTransports); leaseRouter ? leaseRouter->GetCompatibleTransports (false) : (i2p::data::RouterInfo::CompatibleTransports)i2p::data::RouterInfo::eAllTransports);

View File

@ -117,12 +117,12 @@ namespace datagram
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
// TODO: implement calls from other thread from SAM // TODO: implement calls from other thread from SAM
std::shared_ptr<DatagramSession> GetSession(const i2p::data::IdentHash & ident); std::shared_ptr<DatagramSession> GetSession(const i2p::data::IdentHash & ident);
void SendDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); void SendDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
void SendRawDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); void SendRawDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
void FlushSendQueue (std::shared_ptr<DatagramSession> session); void FlushSendQueue (std::shared_ptr<DatagramSession> session);
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false); void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false);
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; }; void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };

View File

@ -89,7 +89,7 @@ namespace client
bool dontpublish = false; bool dontpublish = false;
i2p::config::GetOption (it->second, dontpublish); i2p::config::GetOption (it->second, dontpublish);
m_IsPublic = !dontpublish; m_IsPublic = !dontpublish;
} }
it = params->find (I2CP_PARAM_LEASESET_TYPE); it = params->find (I2CP_PARAM_LEASESET_TYPE);
if (it != params->end ()) if (it != params->end ())
m_LeaseSetType = std::stoi(it->second); m_LeaseSetType = std::stoi(it->second);
@ -367,8 +367,8 @@ namespace client
HandleDatabaseSearchReplyMessage (payload, len); HandleDatabaseSearchReplyMessage (payload, len);
break; break;
case eI2NPShortTunnelBuildReply: // might come as garlic encrypted case eI2NPShortTunnelBuildReply: // might come as garlic encrypted
i2p::HandleI2NPMessage (CreateI2NPMessage (typeID, payload, len, msgID)); i2p::HandleI2NPMessage (CreateI2NPMessage (typeID, payload, len, msgID));
break; break;
default: default:
LogPrint (eLogWarning, "Destination: Unexpected I2NP message type ", typeID); LogPrint (eLogWarning, "Destination: Unexpected I2NP message type ", typeID);
return false; return false;
@ -395,7 +395,7 @@ namespace client
LogPrint (eLogDebug, "Destination: Remote LeaseSet"); LogPrint (eLogDebug, "Destination: Remote LeaseSet");
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex); std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
auto it = m_RemoteLeaseSets.find (key); auto it = m_RemoteLeaseSets.find (key);
if (it != m_RemoteLeaseSets.end () && if (it != m_RemoteLeaseSets.end () &&
it->second->GetStoreType () == buf[DATABASE_STORE_TYPE_OFFSET]) // update only if same type it->second->GetStoreType () == buf[DATABASE_STORE_TYPE_OFFSET]) // update only if same type
{ {
leaseSet = it->second; leaseSet = it->second;
@ -487,7 +487,7 @@ namespace client
i2p::data::IdentHash peerHash (buf + 33 + i*32); i2p::data::IdentHash peerHash (buf + 33 + i*32);
if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash)) if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash))
{ {
LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); LogPrint (eLogInfo, "Destination: Found new floodfill, request it");
i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory
} }
} }
@ -767,11 +767,11 @@ namespace client
uint8_t replyKey[32], replyTag[32]; uint8_t replyKey[32], replyTag[32];
RAND_bytes (replyKey, 32); // random session key RAND_bytes (replyKey, 32); // random session key
RAND_bytes (replyTag, isECIES ? 8 : 32); // random session tag RAND_bytes (replyTag, isECIES ? 8 : 32); // random session tag
if (isECIES) if (isECIES)
AddECIESx25519Key (replyKey, replyTag); AddECIESx25519Key (replyKey, replyTag);
else else
AddSessionKey (replyKey, replyTag); AddSessionKey (replyKey, replyTag);
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest, auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
request->excluded, request->replyTunnel, replyKey, replyTag, isECIES)); request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
request->outboundTunnel->SendTunnelDataMsg ( request->outboundTunnel->SendTunnelDataMsg (
{ {
@ -866,8 +866,8 @@ namespace client
ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys, ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
bool isPublic, const std::map<std::string, std::string> * params): bool isPublic, const std::map<std::string, std::string> * params):
LeaseSetDestination (service, isPublic, params), LeaseSetDestination (service, isPublic, params),
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS),
m_DatagramDestination (nullptr), m_RefCounter (0), m_DatagramDestination (nullptr), m_RefCounter (0),
m_ReadyChecker(service) m_ReadyChecker(service)
@ -916,11 +916,11 @@ namespace client
encryptionKey->GenerateKeys (); encryptionKey->GenerateKeys ();
encryptionKey->CreateDecryptor (); encryptionKey->CreateDecryptor ();
if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
{ {
m_ECIESx25519EncryptionKey.reset (encryptionKey); m_ECIESx25519EncryptionKey.reset (encryptionKey);
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // Rathets must use LeaseSet2 SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // Rathets must use LeaseSet2
} }
else else
m_StandardEncryptionKey.reset (encryptionKey); m_StandardEncryptionKey.reset (encryptionKey);
} }
@ -939,7 +939,7 @@ namespace client
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS); it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
if (it != params->end ()) if (it != params->end ())
i2p::config::GetOption (it->second, m_IsStreamingAnswerPings); i2p::config::GetOption (it->second, m_IsStreamingAnswerPings);
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
{ {
// authentication for encrypted LeaseSet // authentication for encrypted LeaseSet
@ -1099,21 +1099,21 @@ namespace client
void ClientDestination::SendPing (const i2p::data::IdentHash& to) void ClientDestination::SendPing (const i2p::data::IdentHash& to)
{ {
if (m_StreamingDestination) if (m_StreamingDestination)
{ {
auto leaseSet = FindLeaseSet (to); auto leaseSet = FindLeaseSet (to);
if (leaseSet) if (leaseSet)
m_StreamingDestination->SendPing (leaseSet); m_StreamingDestination->SendPing (leaseSet);
else else
{ {
auto s = m_StreamingDestination; auto s = m_StreamingDestination;
RequestDestination (to, RequestDestination (to,
[s](std::shared_ptr<const i2p::data::LeaseSet> ls) [s](std::shared_ptr<const i2p::data::LeaseSet> ls)
{ {
if (ls) s->SendPing (ls); if (ls) s->SendPing (ls);
}); });
} }
} }
} }
void ClientDestination::SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to) void ClientDestination::SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to)
{ {
@ -1122,9 +1122,9 @@ namespace client
[s](std::shared_ptr<const i2p::data::LeaseSet> ls) [s](std::shared_ptr<const i2p::data::LeaseSet> ls)
{ {
if (ls) s->SendPing (ls); if (ls) s->SendPing (ls);
}); });
} }
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const
{ {
if (port) if (port)
@ -1182,18 +1182,18 @@ namespace client
auto ret = it->second; auto ret = it->second;
m_StreamingDestinationsByPorts.erase (it); m_StreamingDestinationsByPorts.erase (it);
return ret; return ret;
} }
} }
return nullptr; return nullptr;
} }
i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination (bool gzip) i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination (bool gzip)
{ {
if (m_DatagramDestination == nullptr) if (m_DatagramDestination == nullptr)
m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis (), gzip); m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis (), gzip);
return m_DatagramDestination; return m_DatagramDestination;
} }
std::vector<std::shared_ptr<const i2p::stream::Stream> > ClientDestination::GetAllStreams () const std::vector<std::shared_ptr<const i2p::stream::Stream> > ClientDestination::GetAllStreams () const
{ {
std::vector<std::shared_ptr<const i2p::stream::Stream> > ret; std::vector<std::shared_ptr<const i2p::stream::Stream> > ret;

View File

@ -68,8 +68,8 @@ namespace client
const char I2CP_PARAM_LEASESET_PRIV_KEY[] = "i2cp.leaseSetPrivKey"; // PSK decryption key, base64 const char I2CP_PARAM_LEASESET_PRIV_KEY[] = "i2cp.leaseSetPrivKey"; // PSK decryption key, base64
const char I2CP_PARAM_LEASESET_AUTH_TYPE[] = "i2cp.leaseSetAuthType"; const char I2CP_PARAM_LEASESET_AUTH_TYPE[] = "i2cp.leaseSetAuthType";
const char I2CP_PARAM_LEASESET_CLIENT_DH[] = "i2cp.leaseSetClient.dh"; // group of i2cp.leaseSetClient.dh.nnn const char I2CP_PARAM_LEASESET_CLIENT_DH[] = "i2cp.leaseSetClient.dh"; // group of i2cp.leaseSetClient.dh.nnn
const char I2CP_PARAM_LEASESET_CLIENT_PSK[] = "i2cp.leaseSetClient.psk"; // group of i2cp.leaseSetClient.psk.nnn const char I2CP_PARAM_LEASESET_CLIENT_PSK[] = "i2cp.leaseSetClient.psk"; // group of i2cp.leaseSetClient.psk.nnn
// latency // latency
const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min"; const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min";
const int DEFAULT_MIN_TUNNEL_LATENCY = 0; const int DEFAULT_MIN_TUNNEL_LATENCY = 0;
@ -80,7 +80,7 @@ namespace client
const char I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY[] = "i2p.streaming.initialAckDelay"; const char I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY[] = "i2p.streaming.initialAckDelay";
const int DEFAULT_INITIAL_ACK_DELAY = 200; // milliseconds const int DEFAULT_INITIAL_ACK_DELAY = 200; // milliseconds
const char I2CP_PARAM_STREAMING_ANSWER_PINGS[] = "i2p.streaming.answerPings"; const char I2CP_PARAM_STREAMING_ANSWER_PINGS[] = "i2p.streaming.answerPings";
const int DEFAULT_ANSWER_PINGS = true; const int DEFAULT_ANSWER_PINGS = true;
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete; typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
@ -139,7 +139,7 @@ namespace client
void SetLeaseSetUpdated (); void SetLeaseSetUpdated ();
bool IsPublic () const { return m_IsPublic; }; bool IsPublic () const { return m_IsPublic; };
void SetPublic (bool pub) { m_IsPublic = pub; }; void SetPublic (bool pub) { m_IsPublic = pub; };
protected: protected:
@ -251,7 +251,7 @@ namespace client
void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor); void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor);
int GetStreamingAckDelay () const { return m_StreamingAckDelay; } int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; } bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; }
// datagram // datagram
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; }; i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
i2p::datagram::DatagramDestination * CreateDatagramDestination (bool gzip = true); i2p::datagram::DatagramDestination * CreateDatagramDestination (bool gzip = true);

View File

@ -90,24 +90,24 @@ namespace garlic
} }
void RatchetTagSet::DeleteSymmKey (int index) void RatchetTagSet::DeleteSymmKey (int index)
{ {
m_ItermediateSymmKeys.erase (index); m_ItermediateSymmKeys.erase (index);
} }
void ReceiveRatchetTagSet::Expire () void ReceiveRatchetTagSet::Expire ()
{ {
if (!m_ExpirationTimestamp) if (!m_ExpirationTimestamp)
m_ExpirationTimestamp = i2p::util::GetSecondsSinceEpoch () + ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT; m_ExpirationTimestamp = i2p::util::GetSecondsSinceEpoch () + ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT;
} }
bool ReceiveRatchetTagSet::IsExpired (uint64_t ts) const bool ReceiveRatchetTagSet::IsExpired (uint64_t ts) const
{ {
return m_ExpirationTimestamp && ts > m_ExpirationTimestamp; return m_ExpirationTimestamp && ts > m_ExpirationTimestamp;
} }
bool ReceiveRatchetTagSet::IsIndexExpired (int index) const bool ReceiveRatchetTagSet::IsIndexExpired (int index) const
{ {
return index < m_TrimBehindIndex; return index < m_TrimBehindIndex;
} }
bool ReceiveRatchetTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index) bool ReceiveRatchetTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index)
@ -115,21 +115,21 @@ namespace garlic
auto session = GetSession (); auto session = GetSession ();
if (!session) return false; if (!session) return false;
return session->HandleNextMessage (buf, len, shared_from_this (), index); return session->HandleNextMessage (buf, len, shared_from_this (), index);
} }
SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key): SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key):
ReceiveRatchetTagSet (nullptr), m_Destination (destination) ReceiveRatchetTagSet (nullptr), m_Destination (destination)
{ {
memcpy (m_Key, key, 32); memcpy (m_Key, key, 32);
Expire (); Expire ();
} }
bool SymmetricKeyTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index) bool SymmetricKeyTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index)
{ {
if (len < 24) return false; if (len < 24) return false;
uint8_t nonce[12]; uint8_t nonce[12];
memset (nonce, 0, 12); // n = 0 memset (nonce, 0, 12); // n = 0
size_t offset = 8; // first 8 bytes is reply tag used as AD size_t offset = 8; // first 8 bytes is reply tag used as AD
len -= 16; // poly1305 len -= 16; // poly1305
if (!i2p::crypto::AEADChaCha20Poly1305 (buf + offset, len - offset, buf, 8, m_Key, nonce, buf + offset, len - offset, false)) // decrypt if (!i2p::crypto::AEADChaCha20Poly1305 (buf + offset, len - offset, buf, 8, m_Key, nonce, buf + offset, len - offset, false)) // decrypt
{ {
@ -137,33 +137,33 @@ namespace garlic
return false; return false;
} }
// we assume 1 I2NP block with delivery type local // we assume 1 I2NP block with delivery type local
if (offset + 3 > len) if (offset + 3 > len)
{ {
LogPrint (eLogWarning, "Garlic: Symmetric key tagset is too short ", len); LogPrint (eLogWarning, "Garlic: Symmetric key tagset is too short ", len);
return false; return false;
} }
if (buf[offset] != eECIESx25519BlkGalicClove) if (buf[offset] != eECIESx25519BlkGalicClove)
{ {
LogPrint (eLogWarning, "Garlic: Symmetric key tagset unexpected block ", (int)buf[offset]); LogPrint (eLogWarning, "Garlic: Symmetric key tagset unexpected block ", (int)buf[offset]);
return false; return false;
} }
offset++; offset++;
auto size = bufbe16toh (buf + offset); auto size = bufbe16toh (buf + offset);
offset += 2; offset += 2;
if (offset + size > len) if (offset + size > len)
{ {
LogPrint (eLogWarning, "Garlic: Symmetric key tagset block is too long ", size); LogPrint (eLogWarning, "Garlic: Symmetric key tagset block is too long ", size);
return false; return false;
} }
if (m_Destination) if (m_Destination)
m_Destination->HandleECIESx25519GarlicClove (buf + offset, size); m_Destination->HandleECIESx25519GarlicClove (buf + offset, size);
return true; return true;
} }
ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSetNS): ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSetNS):
GarlicRoutingSession (owner, true) GarlicRoutingSession (owner, true)
{ {
if (!attachLeaseSetNS) SetLeaseSetUpdateStatus (eLeaseSetUpToDate); if (!attachLeaseSetNS) SetLeaseSetUpdateStatus (eLeaseSetUpToDate);
RAND_bytes (m_PaddingSizes, 32); m_NextPaddingSize = 0; RAND_bytes (m_PaddingSizes, 32); m_NextPaddingSize = 0;
} }
@ -181,11 +181,11 @@ namespace garlic
{ {
bool ineligible = false; bool ineligible = false;
while (!ineligible) while (!ineligible)
{ {
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
ineligible = m_EphemeralKeys->IsElligatorIneligible (); ineligible = m_EphemeralKeys->IsElligatorIneligible ();
if (!ineligible) // we haven't tried it yet if (!ineligible) // we haven't tried it yet
{ {
if (i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys->GetPublicKey (), buf)) if (i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys->GetPublicKey (), buf))
return true; // success return true; // success
// otherwise return back // otherwise return back
@ -194,7 +194,7 @@ namespace garlic
} }
else else
i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys); i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys);
} }
// we still didn't find elligator eligible pair // we still didn't find elligator eligible pair
for (int i = 0; i < 25; i++) for (int i = 0; i < 25; i++)
{ {
@ -208,7 +208,7 @@ namespace garlic
// let NTCP2 use it // let NTCP2 use it
m_EphemeralKeys->SetElligatorIneligible (); m_EphemeralKeys->SetElligatorIneligible ();
i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys); i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys);
} }
} }
LogPrint (eLogError, "Garlic: Can't generate elligator eligible x25519 keys"); LogPrint (eLogError, "Garlic: Can't generate elligator eligible x25519 keys");
return false; return false;
@ -229,7 +229,7 @@ namespace garlic
// we are Bob // we are Bob
// KDF1 // KDF1
i2p::crypto::InitNoiseIKState (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk i2p::crypto::InitNoiseIKState (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk
if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk)) if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk))
{ {
LogPrint (eLogError, "Garlic: Can't decode elligator"); LogPrint (eLogError, "Garlic: Can't decode elligator");
@ -243,7 +243,7 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key"); LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
// decrypt flags/static // decrypt flags/static
@ -267,7 +267,7 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); LogPrint (eLogWarning, "Garlic: Incorrect Alice static key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
} }
else // all zeros flags else // all zeros flags
@ -280,13 +280,13 @@ namespace garlic
LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed"); LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed");
return false; return false;
} }
m_State = eSessionStateNewSessionReceived; m_State = eSessionStateNewSessionReceived;
if (isStatic) if (isStatic)
{ {
MixHash (buf, len); // h = SHA256(h || ciphertext) MixHash (buf, len); // h = SHA256(h || ciphertext)
GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ());
} }
HandlePayload (payload.data (), len - 16, nullptr, 0); HandlePayload (payload.data (), len - 16, nullptr, 0);
return true; return true;
@ -468,7 +468,7 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Bob static key"); LogPrint (eLogWarning, "Garlic: Incorrect Bob static key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
// encrypt flags/static key section // encrypt flags/static key section
uint8_t nonce[12]; uint8_t nonce[12];
@ -478,7 +478,7 @@ namespace garlic
fs = GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); fs = GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD);
else else
{ {
memset (out + offset, 0, 32); // all zeros flags section memset (out + offset, 0, 32); // all zeros flags section
fs = out + offset; fs = out + offset;
} }
if (!i2p::crypto::AEADChaCha20Poly1305 (fs, 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt if (!i2p::crypto::AEADChaCha20Poly1305 (fs, 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt
@ -486,14 +486,14 @@ namespace garlic
LogPrint (eLogWarning, "Garlic: Flags/static section AEAD encryption failed "); LogPrint (eLogWarning, "Garlic: Flags/static section AEAD encryption failed ");
return false; return false;
} }
MixHash (out + offset, 48); // h = SHA256(h || ciphertext) MixHash (out + offset, 48); // h = SHA256(h || ciphertext)
offset += 48; offset += 48;
// KDF2 // KDF2
if (isStatic) if (isStatic)
{ {
GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bpk) GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bpk)
MixKey (sharedSecret); MixKey (sharedSecret);
} }
else else
CreateNonce (1, nonce); CreateNonce (1, nonce);
@ -503,10 +503,10 @@ namespace garlic
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
return false; return false;
} }
m_State = eSessionStateNewSessionSent; m_State = eSessionStateNewSessionSent;
if (isStatic) if (isStatic)
{ {
MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext) MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext)
if (GetOwner ()) if (GetOwner ())
{ {
@ -514,11 +514,11 @@ namespace garlic
InitNewSessionTagset (tagsetNsr); InitNewSessionTagset (tagsetNsr);
tagsetNsr->Expire (); // let non-replied session expire tagsetNsr->Expire (); // let non-replied session expire
GenerateMoreReceiveTags (tagsetNsr, ECIESX25519_NSR_NUM_GENERATED_TAGS); GenerateMoreReceiveTags (tagsetNsr, ECIESX25519_NSR_NUM_GENERATED_TAGS);
} }
} }
return true; return true;
} }
bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
{ {
// we are Bob // we are Bob
@ -545,13 +545,13 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key"); LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // sharedSecret = x25519(besk, apk) if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // sharedSecret = x25519(besk, apk)
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); LogPrint (eLogWarning, "Garlic: Incorrect Alice static key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (0, nonce); CreateNonce (0, nonce);
@ -584,10 +584,10 @@ namespace garlic
} }
m_State = eSessionStateNewSessionReplySent; m_State = eSessionStateNewSessionReplySent;
m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch (); m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch ();
return true; return true;
} }
bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
{ {
// we are Bob and sent NSR already // we are Bob and sent NSR already
@ -637,7 +637,7 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Bob ephemeral key"); LogPrint (eLogWarning, "Garlic: Incorrect Bob ephemeral key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
GetOwner ()->Decrypt (bepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk) GetOwner ()->Decrypt (bepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk)
MixKey (sharedSecret); MixKey (sharedSecret);
@ -704,7 +704,7 @@ namespace garlic
if (GetOwner ()) if (GetOwner ())
GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey); GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey);
return false; return false;
} }
memcpy (out, &tag, 8); memcpy (out, &tag, 8);
// ad = The session tag, 8 bytes // ad = The session tag, 8 bytes
// ciphertext = ENCRYPT(k, n, payload, ad) // ciphertext = ENCRYPT(k, n, payload, ad)
@ -736,7 +736,7 @@ namespace garlic
} }
HandlePayload (payload, len - 16, receiveTagset, index); HandlePayload (payload, len - 16, receiveTagset, index);
if (GetOwner ()) if (GetOwner ())
{ {
int moreTags = 0; int moreTags = 0;
if (GetOwner ()->GetNumRatchetInboundTags () > 0) // override in settings? if (GetOwner ()->GetNumRatchetInboundTags () > 0) // override in settings?
{ {
@ -745,17 +745,17 @@ namespace garlic
index -= GetOwner ()->GetNumRatchetInboundTags (); // trim behind index -= GetOwner ()->GetNumRatchetInboundTags (); // trim behind
} }
else else
{ {
moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4 moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4
if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS; if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS;
moreTags -= (receiveTagset->GetNextIndex () - index); moreTags -= (receiveTagset->GetNextIndex () - index);
index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind
} }
if (moreTags > 0) if (moreTags > 0)
GenerateMoreReceiveTags (receiveTagset, moreTags); GenerateMoreReceiveTags (receiveTagset, moreTags);
if (index > 0) if (index > 0)
receiveTagset->SetTrimBehind (index); receiveTagset->SetTrimBehind (index);
} }
return true; return true;
} }
@ -774,13 +774,13 @@ namespace garlic
#endif #endif
case eSessionStateEstablished: case eSessionStateEstablished:
if (receiveTagset->IsNS ()) if (receiveTagset->IsNS ())
{ {
// our of sequence NSR // our of sequence NSR
LogPrint (eLogDebug, "Garlic: Check for out of order NSR with index ", index); LogPrint (eLogDebug, "Garlic: Check for out of order NSR with index ", index);
if (receiveTagset->GetNextIndex () - index < ECIESX25519_NSR_NUM_GENERATED_TAGS/2) if (receiveTagset->GetNextIndex () - index < ECIESX25519_NSR_NUM_GENERATED_TAGS/2)
GenerateMoreReceiveTags (receiveTagset, ECIESX25519_NSR_NUM_GENERATED_TAGS); GenerateMoreReceiveTags (receiveTagset, ECIESX25519_NSR_NUM_GENERATED_TAGS);
return HandleNewOutgoingSessionReply (buf, len); return HandleNewOutgoingSessionReply (buf, len);
} }
else else
return HandleExistingSessionMessage (buf, len, receiveTagset, index); return HandleExistingSessionMessage (buf, len, receiveTagset, index);
case eSessionStateNew: case eSessionStateNew:
@ -792,7 +792,7 @@ namespace garlic
} }
return true; return true;
} }
std::shared_ptr<I2NPMessage> ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) std::shared_ptr<I2NPMessage> ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg)
{ {
uint8_t * payload = GetOwner ()->GetPayloadBuffer (); uint8_t * payload = GetOwner ()->GetPayloadBuffer ();
@ -829,7 +829,7 @@ namespace garlic
if (!NewOutgoingSessionMessage (payload, len, buf, m->maxLen, false)) if (!NewOutgoingSessionMessage (payload, len, buf, m->maxLen, false))
return nullptr; return nullptr;
len += 96; len += 96;
break; break;
default: default:
return nullptr; return nullptr;
} }
@ -844,18 +844,18 @@ namespace garlic
{ {
m_State = eSessionStateOneTime; m_State = eSessionStateOneTime;
return WrapSingleMessage (msg); return WrapSingleMessage (msg);
} }
size_t ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t * payload) size_t ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t * payload)
{ {
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
size_t payloadLen = 0; size_t payloadLen = 0;
if (first) payloadLen += 7;// datatime if (first) payloadLen += 7;// datatime
if (msg) if (msg)
{ {
payloadLen += msg->GetPayloadLength () + 13; payloadLen += msg->GetPayloadLength () + 13;
if (m_Destination) payloadLen += 32; if (m_Destination) payloadLen += 32;
} }
if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT) if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)
{ {
// resubmit non-confirmed LeaseSet // resubmit non-confirmed LeaseSet
@ -896,9 +896,9 @@ namespace garlic
paddingSize = m_PaddingSizes[m_NextPaddingSize++] & 0x0F; // 0 - 15 paddingSize = m_PaddingSizes[m_NextPaddingSize++] & 0x0F; // 0 - 15
if (m_NextPaddingSize >= 32) if (m_NextPaddingSize >= 32)
{ {
RAND_bytes (m_PaddingSizes, 32); RAND_bytes (m_PaddingSizes, 32);
m_NextPaddingSize = 0; m_NextPaddingSize = 0;
} }
if (delta > 3) if (delta > 3)
{ {
delta -= 3; delta -= 3;
@ -914,7 +914,7 @@ namespace garlic
{ {
LogPrint (eLogError, "Garlic: Payload length ", payloadLen, " is too long"); LogPrint (eLogError, "Garlic: Payload length ", payloadLen, " is too long");
return 0; return 0;
} }
m_LastSentTimestamp = ts; m_LastSentTimestamp = ts;
size_t offset = 0; size_t offset = 0;
// DateTime // DateTime
@ -993,7 +993,7 @@ namespace garlic
htobe16buf (payload + offset, paddingSize); offset += 2; htobe16buf (payload + offset, paddingSize); offset += 2;
memset (payload + offset, 0, paddingSize); offset += paddingSize; memset (payload + offset, 0, paddingSize); offset += paddingSize;
} }
} }
return payloadLen; return payloadLen;
} }
@ -1050,17 +1050,17 @@ namespace garlic
void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int numTags) void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int numTags)
{ {
if (GetOwner ()) if (GetOwner ())
{ {
for (int i = 0; i < numTags; i++) for (int i = 0; i < numTags; i++)
{ {
auto tag = GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset); auto tag = GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset);
if (!tag) if (!tag)
{ {
LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for receive tagset"); LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for receive tagset");
break; break;
} }
} }
} }
} }
bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts) bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts)
@ -1073,9 +1073,9 @@ namespace garlic
RouterIncomingRatchetSession::RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState): RouterIncomingRatchetSession::RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState):
ECIESX25519AEADRatchetSession (&i2p::context, false) ECIESX25519AEADRatchetSession (&i2p::context, false)
{ {
SetLeaseSetUpdateStatus (eLeaseSetDoNotSend); SetLeaseSetUpdateStatus (eLeaseSetDoNotSend);
SetNoiseState (initState); SetNoiseState (initState);
} }
bool RouterIncomingRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len) bool RouterIncomingRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len)
{ {
@ -1088,12 +1088,12 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect N ephemeral public key"); LogPrint (eLogWarning, "Garlic: Incorrect N ephemeral public key");
return false; return false;
} }
m_CurrentNoiseState.MixKey (sharedSecret); m_CurrentNoiseState.MixKey (sharedSecret);
buf += 32; len -= 32; buf += 32; len -= 32;
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (0, nonce); CreateNonce (0, nonce);
std::vector<uint8_t> payload (len - 16); std::vector<uint8_t> payload (len - 16);
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_CurrentNoiseState.m_H, 32, if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_CurrentNoiseState.m_H, 32,
m_CurrentNoiseState.m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt m_CurrentNoiseState.m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt
{ {
@ -1102,20 +1102,20 @@ namespace garlic
} }
HandlePayload (payload.data (), len - 16, nullptr, 0); HandlePayload (payload.data (), len - 16, nullptr, 0);
return true; return true;
} }
static size_t CreateGarlicPayload (std::shared_ptr<const I2NPMessage> msg, uint8_t * payload, static size_t CreateGarlicPayload (std::shared_ptr<const I2NPMessage> msg, uint8_t * payload,
bool datetime, size_t optimalSize) bool datetime, size_t optimalSize)
{ {
size_t len = 0; size_t len = 0;
if (datetime) if (datetime)
{ {
// DateTime // DateTime
payload[0] = eECIESx25519BlkDateTime; payload[0] = eECIESx25519BlkDateTime;
htobe16buf (payload + 1, 4); htobe16buf (payload + 1, 4);
htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ()); htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ());
len = 7; len = 7;
} }
// I2NP // I2NP
payload += len; payload += len;
uint16_t cloveSize = msg->GetPayloadLength () + 10; uint16_t cloveSize = msg->GetPayloadLength () + 10;
@ -1139,14 +1139,14 @@ namespace garlic
delta -= 3; delta -= 3;
if (paddingSize > delta) paddingSize %= delta; if (paddingSize > delta) paddingSize %= delta;
} }
payload[0] = eECIESx25519BlkPadding; payload[0] = eECIESx25519BlkPadding;
htobe16buf (payload + 1, paddingSize); htobe16buf (payload + 1, paddingSize);
if (paddingSize) memset (payload + 3, 0, paddingSize); if (paddingSize) memset (payload + 3, 0, paddingSize);
len += paddingSize + 3; len += paddingSize + 3;
} }
return len; return len;
} }
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag) std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag)
{ {
auto m = NewI2NPMessage (); auto m = NewI2NPMessage ();
@ -1188,8 +1188,8 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Bob static key"); LogPrint (eLogWarning, "Garlic: Incorrect Bob static key");
return nullptr; return nullptr;
} }
noiseState.MixKey (sharedSecret); noiseState.MixKey (sharedSecret);
auto payload = buf + offset; auto payload = buf + offset;
size_t len = CreateGarlicPayload (msg, payload, true, 900); // 1003 - 32 eph key - 16 Poly1305 hash - 16 I2NP header - 4 garlic length - 35 router tunnel delivery size_t len = CreateGarlicPayload (msg, payload, true, 900); // 1003 - 32 eph key - 16 Poly1305 hash - 16 I2NP header - 4 garlic length - 35 router tunnel delivery
uint8_t nonce[12]; uint8_t nonce[12];
@ -1205,6 +1205,6 @@ namespace garlic
m->len += offset + 4; m->len += offset + 4;
m->FillI2NPMessageHeader (eI2NPGarlic); m->FillI2NPMessageHeader (eI2NPGarlic);
return m; return m;
} }
} }
} }

View File

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 2013-2021, The PurpleI2P Project * Copyright (c) 2013-2021, The PurpleI2P Project
* *
@ -28,7 +27,7 @@ namespace garlic
{ {
const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second since session creation we can restart session after const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second since session creation we can restart session after
const int ECIESX25519_INACTIVITY_TIMEOUT = 90; // number of seconds we receive nothing and should restart if we can const int ECIESX25519_INACTIVITY_TIMEOUT = 90; // number of seconds we receive nothing and should restart if we can
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds
const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180 const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180
@ -46,7 +45,7 @@ namespace garlic
RatchetTagSet () {}; RatchetTagSet () {};
virtual ~RatchetTagSet () {}; virtual ~RatchetTagSet () {};
void DHInitialize (const uint8_t * rootKey, const uint8_t * k); void DHInitialize (const uint8_t * rootKey, const uint8_t * k);
void NextSessionTagRatchet (); void NextSessionTagRatchet ();
uint64_t GetNextSessionTag (); uint64_t GetNextSessionTag ();
@ -57,14 +56,14 @@ namespace garlic
int GetTagSetID () const { return m_TagSetID; }; int GetTagSetID () const { return m_TagSetID; };
void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; }; void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; };
private: private:
i2p::data::Tag<64> m_SessionTagKeyData; i2p::data::Tag<64> m_SessionTagKeyData;
uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64], m_NextRootKey[32]; uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64], m_NextRootKey[32];
int m_NextIndex, m_NextSymmKeyIndex; int m_NextIndex, m_NextSymmKeyIndex;
std::unordered_map<int, i2p::data::Tag<32> > m_ItermediateSymmKeys; std::unordered_map<int, i2p::data::Tag<32> > m_ItermediateSymmKeys;
int m_TagSetID = 0; int m_TagSetID = 0;
}; };
@ -74,27 +73,27 @@ namespace garlic
{ {
public: public:
ReceiveRatchetTagSet (std::shared_ptr<ECIESX25519AEADRatchetSession> session, bool isNS = false): ReceiveRatchetTagSet (std::shared_ptr<ECIESX25519AEADRatchetSession> session, bool isNS = false):
m_Session (session), m_IsNS (isNS) {}; m_Session (session), m_IsNS (isNS) {};
bool IsNS () const { return m_IsNS; }; bool IsNS () const { return m_IsNS; };
std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession () { return m_Session; }; std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession () { return m_Session; };
void SetTrimBehind (int index) { if (index > m_TrimBehindIndex) m_TrimBehindIndex = index; }; void SetTrimBehind (int index) { if (index > m_TrimBehindIndex) m_TrimBehindIndex = index; };
int GetTrimBehind () const { return m_TrimBehindIndex; }; int GetTrimBehind () const { return m_TrimBehindIndex; };
void Expire (); void Expire ();
bool IsExpired (uint64_t ts) const; bool IsExpired (uint64_t ts) const;
virtual bool IsIndexExpired (int index) const; virtual bool IsIndexExpired (int index) const;
virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index); virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index);
private: private:
int m_TrimBehindIndex = 0; int m_TrimBehindIndex = 0;
std::shared_ptr<ECIESX25519AEADRatchetSession> m_Session; std::shared_ptr<ECIESX25519AEADRatchetSession> m_Session;
bool m_IsNS; bool m_IsNS;
uint64_t m_ExpirationTimestamp = 0; uint64_t m_ExpirationTimestamp = 0;
}; };
class SymmetricKeyTagSet: public ReceiveRatchetTagSet class SymmetricKeyTagSet: public ReceiveRatchetTagSet
{ {
@ -104,13 +103,13 @@ namespace garlic
bool IsIndexExpired (int index) const { return false; }; bool IsIndexExpired (int index) const { return false; };
bool HandleNextMessage (uint8_t * buf, size_t len, int index); bool HandleNextMessage (uint8_t * buf, size_t len, int index);
private: private:
GarlicDestination * m_Destination; GarlicDestination * m_Destination;
uint8_t m_Key[32]; uint8_t m_Key[32];
}; };
enum ECIESx25519BlockType enum ECIESx25519BlockType
{ {
eECIESx25519BlkDateTime = 0, eECIESx25519BlkDateTime = 0,
@ -128,7 +127,7 @@ namespace garlic
const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02; const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02;
const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04; const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04;
class ECIESX25519AEADRatchetSession: public GarlicRoutingSession, class ECIESX25519AEADRatchetSession: public GarlicRoutingSession,
private i2p::crypto::NoiseSymmetricState, private i2p::crypto::NoiseSymmetricState,
public std::enable_shared_from_this<ECIESX25519AEADRatchetSession> public std::enable_shared_from_this<ECIESX25519AEADRatchetSession>
{ {
@ -158,10 +157,10 @@ namespace garlic
bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int index = 0); bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int index = 0);
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg); std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
std::shared_ptr<I2NPMessage> WrapOneTimeMessage (std::shared_ptr<const I2NPMessage> msg); std::shared_ptr<I2NPMessage> WrapOneTimeMessage (std::shared_ptr<const I2NPMessage> msg);
const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; }
void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); } void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); }
void Terminate () { m_IsTerminated = true; } void Terminate () { m_IsTerminated = true; }
void SetDestination (const i2p::data::IdentHash& dest) // TODO: void SetDestination (const i2p::data::IdentHash& dest) // TODO:
{ {
@ -171,19 +170,19 @@ namespace garlic
bool CheckExpired (uint64_t ts); // true is expired bool CheckExpired (uint64_t ts); // true is expired
bool CanBeRestarted (uint64_t ts) const { return ts > m_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT; } bool CanBeRestarted (uint64_t ts) const { return ts > m_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT; }
bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); } bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); }
bool IsRatchets () const { return true; }; bool IsRatchets () const { return true; };
bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; }; bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; };
bool IsTerminated () const { return m_IsTerminated; } bool IsTerminated () const { return m_IsTerminated; }
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; }; uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
protected: protected:
i2p::crypto::NoiseSymmetricState& GetNoiseState () { return *this; }; i2p::crypto::NoiseSymmetricState& GetNoiseState () { return *this; };
void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; }; void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; };
void CreateNonce (uint64_t seqn, uint8_t * nonce); void CreateNonce (uint64_t seqn, uint8_t * nonce);
void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& receiveTagset, int index); void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& receiveTagset, int index);
private: private:
bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes
@ -198,7 +197,7 @@ namespace garlic
bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
bool NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
size_t CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t * payload); size_t CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t * payload);
size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len); size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len);
size_t CreateLeaseSetClove (std::shared_ptr<const i2p::data::LocalLeaseSet> ls, uint64_t ts, uint8_t * buf, size_t len); size_t CreateLeaseSetClove (std::shared_ptr<const i2p::data::LocalLeaseSet> ls, uint64_t ts, uint8_t * buf, size_t len);
@ -221,7 +220,7 @@ namespace garlic
bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false; bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false;
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet; std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
uint8_t m_PaddingSizes[32], m_NextPaddingSize; uint8_t m_PaddingSizes[32], m_NextPaddingSize;
public: public:
// for HTTP only // for HTTP only
@ -240,12 +239,12 @@ namespace garlic
RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState); RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState);
bool HandleNextMessage (const uint8_t * buf, size_t len); bool HandleNextMessage (const uint8_t * buf, size_t len);
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; }; i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
private: private:
i2p::crypto::NoiseSymmetricState m_CurrentNoiseState; i2p::crypto::NoiseSymmetricState m_CurrentNoiseState;
}; };
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag); std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag);
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey); std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey);
} }

View File

@ -452,7 +452,7 @@ namespace garlic
{ {
it.second->Terminate (); it.second->Terminate ();
it.second->SetOwner (nullptr); it.second->SetOwner (nullptr);
} }
m_ECIESx25519Sessions.clear (); m_ECIESx25519Sessions.clear ();
m_ECIESx25519Tags.clear (); m_ECIESx25519Tags.clear ();
} }
@ -470,14 +470,14 @@ namespace garlic
uint64_t t; uint64_t t;
memcpy (&t, tag, 8); memcpy (&t, tag, 8);
AddECIESx25519Key (key, t); AddECIESx25519Key (key, t);
} }
void GarlicDestination::AddECIESx25519Key (const uint8_t * key, uint64_t tag) void GarlicDestination::AddECIESx25519Key (const uint8_t * key, uint64_t tag)
{ {
auto tagset = std::make_shared<SymmetricKeyTagSet>(this, key); auto tagset = std::make_shared<SymmetricKeyTagSet>(this, key);
m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{0, tagset}); m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{0, tagset});
} }
bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
{ {
AddSessionKey (key, tag); AddSessionKey (key, tag);
@ -498,10 +498,10 @@ namespace garlic
bool found = false; bool found = false;
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
// try ECIESx25519 tag // try ECIESx25519 tag
found = HandleECIESx25519TagMessage (buf, length); found = HandleECIESx25519TagMessage (buf, length);
if (!found) if (!found)
{ {
auto it = !mod ? m_Tags.find (SessionTag(buf)) : m_Tags.end (); // AES block is multiple of 16 auto it = !mod ? m_Tags.find (SessionTag(buf)) : m_Tags.end (); // AES block is multiple of 16
// AES tag might be used even if encryption type is not ElGamal/AES // AES tag might be used even if encryption type is not ElGamal/AES
if (it != m_Tags.end ()) // try AES tag if (it != m_Tags.end ()) // try AES tag
@ -542,7 +542,7 @@ namespace garlic
auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming
if (!session->HandleNextMessage (buf, length, nullptr, 0)) if (!session->HandleNextMessage (buf, length, nullptr, 0))
{ {
// try to generate more tags for last tagset // try to generate more tags for last tagset
if (m_LastTagset && (m_LastTagset->GetNextIndex () - m_LastTagset->GetTrimBehind () < 3*ECIESX25519_MAX_NUM_GENERATED_TAGS)) if (m_LastTagset && (m_LastTagset->GetNextIndex () - m_LastTagset->GetTrimBehind () < 3*ECIESX25519_MAX_NUM_GENERATED_TAGS))
{ {
uint64_t missingTag; memcpy (&missingTag, buf, 8); uint64_t missingTag; memcpy (&missingTag, buf, 8);
@ -555,24 +555,24 @@ namespace garlic
{ {
LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for last tagset"); LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for last tagset");
break; break;
} }
if (nextTag == missingTag) if (nextTag == missingTag)
{ {
LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated"); LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated");
if (m_LastTagset->HandleNextMessage (buf, length, m_ECIESx25519Tags[nextTag].index)) if (m_LastTagset->HandleNextMessage (buf, length, m_ECIESx25519Tags[nextTag].index))
found = true; found = true;
break; break;
} }
} }
if (!found) m_LastTagset = nullptr; if (!found) m_LastTagset = nullptr;
} }
if (!found) if (!found)
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
} }
} }
else else
LogPrint (eLogError, "Garlic: Failed to decrypt message"); LogPrint (eLogError, "Garlic: Failed to decrypt message");
} }
} }
} }
@ -585,14 +585,14 @@ namespace garlic
{ {
if (it->second.tagset->HandleNextMessage (buf, len, it->second.index)) if (it->second.tagset->HandleNextMessage (buf, len, it->second.index))
m_LastTagset = it->second.tagset; m_LastTagset = it->second.tagset;
else else
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
m_ECIESx25519Tags.erase (it); m_ECIESx25519Tags.erase (it);
return true; return true;
} }
return false; return false;
} }
void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption, void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
std::shared_ptr<i2p::tunnel::InboundTunnel> from) std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{ {
@ -759,10 +759,10 @@ namespace garlic
if (router->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) if (router->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
return WrapECIESX25519MessageForRouter (msg, router->GetIdentity ()->GetEncryptionPublicKey ()); return WrapECIESX25519MessageForRouter (msg, router->GetIdentity ()->GetEncryptionPublicKey ());
else else
{ {
auto session = GetRoutingSession (router, false); auto session = GetRoutingSession (router, false);
return session->WrapSingleMessage (msg); return session->WrapSingleMessage (msg);
} }
} }
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession ( std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
@ -776,14 +776,14 @@ namespace garlic
destination->Encrypt (nullptr, staticKey); // we are supposed to get static key destination->Encrypt (nullptr, staticKey); // we are supposed to get static key
auto it = m_ECIESx25519Sessions.find (staticKey); auto it = m_ECIESx25519Sessions.find (staticKey);
if (it != m_ECIESx25519Sessions.end ()) if (it != m_ECIESx25519Sessions.end ())
{ {
session = it->second; session = it->second;
if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ())) if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ()))
{ {
LogPrint (eLogDebug, "Garlic: Session restarted"); LogPrint (eLogDebug, "Garlic: Session restarted");
session = nullptr; session = nullptr;
} }
} }
if (!session) if (!session)
{ {
session = std::make_shared<ECIESX25519AEADRatchetSession> (this, true); session = std::make_shared<ECIESX25519AEADRatchetSession> (this, true);
@ -879,18 +879,18 @@ namespace garlic
it->second.tagset->DeleteSymmKey (it->second.index); it->second.tagset->DeleteSymmKey (it->second.index);
it = m_ECIESx25519Tags.erase (it); it = m_ECIESx25519Tags.erase (it);
numExpiredTags++; numExpiredTags++;
} }
else else
{ {
auto session = it->second.tagset->GetSession (); auto session = it->second.tagset->GetSession ();
if (!session || session->IsTerminated()) if (!session || session->IsTerminated())
{ {
it = m_ECIESx25519Tags.erase (it); it = m_ECIESx25519Tags.erase (it);
numExpiredTags++; numExpiredTags++;
} }
else else
++it; ++it;
} }
} }
if (numExpiredTags > 0) if (numExpiredTags > 0)
LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " ECIESx25519 tags expired for ", GetIdentHash().ToBase64 ()); LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " ECIESx25519 tags expired for ", GetIdentHash().ToBase64 ());
@ -1099,10 +1099,10 @@ namespace garlic
if (it != m_ECIESx25519Sessions.end ()) if (it != m_ECIESx25519Sessions.end ())
{ {
if (it->second->CanBeRestarted (i2p::util::GetSecondsSinceEpoch ())) if (it->second->CanBeRestarted (i2p::util::GetSecondsSinceEpoch ()))
{ {
it->second->Terminate (); // detach it->second->Terminate (); // detach
m_ECIESx25519Sessions.erase (it); m_ECIESx25519Sessions.erase (it);
} }
else else
{ {
LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists"); LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists");
@ -1127,6 +1127,6 @@ namespace garlic
if (!m_PayloadBuffer) if (!m_PayloadBuffer)
m_PayloadBuffer = new uint8_t[I2NP_MAX_MESSAGE_SIZE]; m_PayloadBuffer = new uint8_t[I2NP_MAX_MESSAGE_SIZE];
return m_PayloadBuffer; return m_PayloadBuffer;
} }
} }
} }

View File

@ -115,7 +115,7 @@ namespace garlic
virtual bool MessageConfirmed (uint32_t msgID); virtual bool MessageConfirmed (uint32_t msgID);
virtual bool IsRatchets () const { return false; }; virtual bool IsRatchets () const { return false; };
virtual bool IsReadyToSend () const { return true; }; virtual bool IsReadyToSend () const { return true; };
virtual bool IsTerminated () const { return !GetOwner (); }; virtual bool IsTerminated () const { return !GetOwner (); };
virtual uint64_t GetLastActivityTimestamp () const { return 0; }; // non-zero for rathets only virtual uint64_t GetLastActivityTimestamp () const { return 0; }; // non-zero for rathets only
void SetLeaseSetUpdated () void SetLeaseSetUpdated ()
@ -251,7 +251,7 @@ namespace garlic
void RemoveECIESx25519Session (const uint8_t * staticKey); void RemoveECIESx25519Session (const uint8_t * staticKey);
void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len); void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len);
uint8_t * GetPayloadBuffer (); uint8_t * GetPayloadBuffer ();
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg); virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg); virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
virtual void SetLeaseSetUpdated (); virtual void SetLeaseSetUpdated ();

View File

@ -14,9 +14,9 @@
#include "Base.h" #include "Base.h"
#include "HTTP.h" #include "HTTP.h"
namespace i2p namespace i2p
{ {
namespace http namespace http
{ {
const std::vector<std::string> HTTP_METHODS = { const std::vector<std::string> HTTP_METHODS = {
"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "CONNECT", // HTTP basic methods "GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "CONNECT", // HTTP basic methods
@ -476,14 +476,14 @@ namespace http
return ptr; return ptr;
} }
std::string UrlDecode(const std::string& data, bool allow_null) std::string UrlDecode(const std::string& data, bool allow_null)
{ {
std::string decoded(data); std::string decoded(data);
size_t pos = 0; size_t pos = 0;
while ((pos = decoded.find('%', pos)) != std::string::npos) while ((pos = decoded.find('%', pos)) != std::string::npos)
{ {
char c = strtol(decoded.substr(pos + 1, 2).c_str(), NULL, 16); char c = strtol(decoded.substr(pos + 1, 2).c_str(), NULL, 16);
if (c == '\0' && !allow_null) if (c == '\0' && !allow_null)
{ {
pos += 3; pos += 3;
continue; continue;
@ -494,10 +494,10 @@ namespace http
return decoded; return decoded;
} }
bool MergeChunkedResponse (std::istream& in, std::ostream& out) bool MergeChunkedResponse (std::istream& in, std::ostream& out)
{ {
std::string hexLen; std::string hexLen;
while (!in.eof ()) while (!in.eof ())
{ {
std::getline (in, hexLen); std::getline (in, hexLen);
errno = 0; errno = 0;
@ -522,6 +522,6 @@ namespace http
if (user.empty () && pass.empty ()) return ""; if (user.empty () && pass.empty ()) return "";
return "Basic " + i2p::data::ToBase64Standard (user + ":" + pass); return "Basic " + i2p::data::ToBase64Standard (user + ":" + pass);
} }
} // http } // http
} // i2p } // i2p

View File

@ -167,8 +167,8 @@ namespace http
*/ */
bool MergeChunkedResponse (std::istream& in, std::ostream& out); bool MergeChunkedResponse (std::istream& in, std::ostream& out);
std::string CreateBasicAuthorizationString (const std::string& user, const std::string& pass); std::string CreateBasicAuthorizationString (const std::string& user, const std::string& pass);
} // http } // http
} // i2p } // i2p

View File

@ -170,8 +170,8 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills, const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
const uint8_t * replyTag, bool replyECIES) const uint8_t * replyTag, bool replyECIES)
{ {
int cnt = excludedFloodfills.size (); int cnt = excludedFloodfills.size ();
auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage (); auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage ();
@ -243,8 +243,8 @@ namespace i2p
return m; return m;
} }
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router, std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router,
uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel) uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
{ {
if (!router) // we send own RouterInfo if (!router) // we send own RouterInfo
router = context.GetSharedRouterInfo (); router = context.GetSharedRouterInfo ();
@ -398,7 +398,7 @@ namespace i2p
retCode = 30; // always reject with bandwidth reason (30) retCode = 30; // always reject with bandwidth reason (30)
memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode; record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
// encrypt reply // encrypt reply
i2p::crypto::CBCEncryption encryption; i2p::crypto::CBCEncryption encryption;
for (int j = 0; j < num; j++) for (int j = 0; j < num; j++)
@ -409,7 +409,7 @@ namespace i2p
uint8_t nonce[12]; uint8_t nonce[12];
memset (nonce, 0, 12); memset (nonce, 0, 12);
auto& noiseState = i2p::context.GetCurrentNoiseState (); auto& noiseState = i2p::context.GetCurrentNoiseState ();
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16, if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16,
noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
{ {
LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed"); LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed");
@ -547,7 +547,7 @@ namespace i2p
{ {
LogPrint (eLogDebug, "I2NP: Short request record ", i, " is ours"); LogPrint (eLogDebug, "I2NP: Short request record ", i, " is ours");
uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE]; uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE];
if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText))
{ {
LogPrint (eLogWarning, "I2NP: Can't decrypt short request record ", i); LogPrint (eLogWarning, "I2NP: Can't decrypt short request record ", i);
return; return;
@ -558,10 +558,10 @@ namespace i2p
return; return;
} }
auto& noiseState = i2p::context.GetCurrentNoiseState (); auto& noiseState = i2p::context.GetCurrentNoiseState ();
uint8_t replyKey[32], layerKey[32], ivKey[32]; uint8_t replyKey[32], layerKey[32], ivKey[32];
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelReplyKey", noiseState.m_CK); i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelReplyKey", noiseState.m_CK);
memcpy (replyKey, noiseState.m_CK + 32, 32); memcpy (replyKey, noiseState.m_CK + 32, 32);
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK); i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK);
memcpy (layerKey, noiseState.m_CK + 32, 32); memcpy (layerKey, noiseState.m_CK + 32, 32);
bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG;
if (isEndpoint) if (isEndpoint)
@ -602,8 +602,8 @@ namespace i2p
if (j == i) if (j == i)
{ {
memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode; reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode;
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16, if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16,
noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
{ {
LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed"); LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed");
@ -611,7 +611,7 @@ namespace i2p
} }
} }
else else
i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply); i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply);
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE; reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
} }
// send reply // send reply
@ -620,10 +620,10 @@ namespace i2p
auto replyMsg = NewI2NPShortMessage (); auto replyMsg = NewI2NPShortMessage ();
replyMsg->Concat (buf, len); replyMsg->Concat (buf, len);
replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)); replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (), if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (),
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local? clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local?
{ {
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK); i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK);
uint64_t tag; uint64_t tag;
memcpy (&tag, noiseState.m_CK, 8); memcpy (&tag, noiseState.m_CK, 8);
// we send it to reply tunnel // we send it to reply tunnel

View File

@ -56,7 +56,7 @@ namespace i2p
// TunnelBuild // TunnelBuild
const size_t TUNNEL_BUILD_RECORD_SIZE = 528; const size_t TUNNEL_BUILD_RECORD_SIZE = 528;
const size_t SHORT_TUNNEL_BUILD_RECORD_SIZE = 218; const size_t SHORT_TUNNEL_BUILD_RECORD_SIZE = 218;
// BuildRequestRecordEncrypted // BuildRequestRecordEncrypted
const size_t BUILD_REQUEST_RECORD_TO_PEER_OFFSET = 0; const size_t BUILD_REQUEST_RECORD_TO_PEER_OFFSET = 0;
const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16; const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16;
@ -98,7 +98,7 @@ namespace i2p
// ShortResponseRecord // ShortResponseRecord
const size_t SHORT_RESPONSE_RECORD_OPTIONS_OFFSET = 0; const size_t SHORT_RESPONSE_RECORD_OPTIONS_OFFSET = 0;
const size_t SHORT_RESPONSE_RECORD_RET_OFFSET = 201; const size_t SHORT_RESPONSE_RECORD_RET_OFFSET = 201;
enum I2NPMessageType enum I2NPMessageType
{ {
eI2NPDummyMsg = 0, eI2NPDummyMsg = 0,
@ -273,8 +273,8 @@ namespace tunnel
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr); uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills, const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false); const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false);
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers); std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);

View File

@ -53,9 +53,9 @@ namespace data
{ {
memcpy (m_StandardIdentity.publicKey, publicKey, 32); memcpy (m_StandardIdentity.publicKey, publicKey, 32);
RAND_bytes (m_StandardIdentity.publicKey + 32, 224); RAND_bytes (m_StandardIdentity.publicKey + 32, 224);
} }
else else
memcpy (m_StandardIdentity.publicKey, publicKey, 256); memcpy (m_StandardIdentity.publicKey, publicKey, 256);
if (type != SIGNING_KEY_TYPE_DSA_SHA1) if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{ {
size_t excessLen = 0; size_t excessLen = 0;
@ -128,7 +128,7 @@ namespace data
{ {
LogPrint (eLogError, "Identity: Unexpected excessive signing key len ", excessLen); LogPrint (eLogError, "Identity: Unexpected excessive signing key len ", excessLen);
excessLen = MAX_EXTENDED_BUFFER_SIZE - 4; excessLen = MAX_EXTENDED_BUFFER_SIZE - 4;
} }
memcpy (m_ExtendedBuffer + 4, excessBuf, excessLen); memcpy (m_ExtendedBuffer + 4, excessBuf, excessLen);
delete[] excessBuf; delete[] excessBuf;
} }
@ -480,7 +480,7 @@ namespace data
size_t ret = m_Public->FromBuffer (buf, len); size_t ret = m_Public->FromBuffer (buf, len);
auto cryptoKeyLen = GetPrivateKeyLen (); auto cryptoKeyLen = GetPrivateKeyLen ();
if (!ret || ret + cryptoKeyLen > len) return 0; // overflow if (!ret || ret + cryptoKeyLen > len) return 0; // overflow
memcpy (m_PrivateKey, buf + ret, cryptoKeyLen); memcpy (m_PrivateKey, buf + ret, cryptoKeyLen);
ret += cryptoKeyLen; ret += cryptoKeyLen;
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen (); size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
if(signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; // overflow if(signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; // overflow
@ -654,9 +654,9 @@ namespace data
size_t PrivateKeys::GetPrivateKeyLen () const size_t PrivateKeys::GetPrivateKeyLen () const
{ {
// private key length always 256, but type 4 // private key length always 256, but type 4
return (m_Public->GetCryptoKeyType () == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) ? 32 : 256; return (m_Public->GetCryptoKeyType () == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) ? 32 : 256;
} }
uint8_t * PrivateKeys::GetPadding() uint8_t * PrivateKeys::GetPadding()
{ {
if(m_Public->GetSigningKeyType () == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519) if(m_Public->GetSigningKeyType () == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
@ -681,7 +681,7 @@ namespace data
break; break;
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD:
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key); return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key);
break; break;
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST: case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
return std::make_shared<i2p::crypto::ECIESP256Decryptor>(key); return std::make_shared<i2p::crypto::ECIESP256Decryptor>(key);

View File

@ -84,9 +84,9 @@ namespace data
typedef uint16_t SigningKeyType; typedef uint16_t SigningKeyType;
typedef uint16_t CryptoKeyType; typedef uint16_t CryptoKeyType;
const size_t MAX_EXTENDED_BUFFER_SIZE = 8; // cryptoKeyType + signingKeyType + 4 extra bytes of P521 const size_t MAX_EXTENDED_BUFFER_SIZE = 8; // cryptoKeyType + signingKeyType + 4 extra bytes of P521
class IdentityEx class IdentityEx
{ {
public: public:
IdentityEx (); IdentityEx ();
@ -138,7 +138,7 @@ namespace data
mutable i2p::crypto::Verifier * m_Verifier = nullptr; mutable i2p::crypto::Verifier * m_Verifier = nullptr;
mutable std::mutex m_VerifierMutex; mutable std::mutex m_VerifierMutex;
size_t m_ExtendedLen; size_t m_ExtendedLen;
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE]; uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
}; };
class PrivateKeys // for eepsites class PrivateKeys // for eepsites

View File

@ -77,7 +77,7 @@ namespace data
LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen); LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen);
m_IsValid = false; m_IsValid = false;
return; return;
} }
uint8_t num = m_Buffer[size]; uint8_t num = m_Buffer[size];
size++; // num size++; // num
LogPrint (eLogDebug, "LeaseSet: Read num=", (int)num); LogPrint (eLogDebug, "LeaseSet: Read num=", (int)num);
@ -87,13 +87,13 @@ namespace data
m_IsValid = false; m_IsValid = false;
return; return;
} }
if (size + num*LEASE_SIZE > m_BufferLen) if (size + num*LEASE_SIZE > m_BufferLen)
{ {
LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen); LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen);
m_IsValid = false; m_IsValid = false;
return; return;
} }
UpdateLeasesBegin (); UpdateLeasesBegin ();
// process leases // process leases
m_ExpirationTime = 0; m_ExpirationTime = 0;
@ -121,13 +121,13 @@ namespace data
// verify // verify
if (verifySignature) if (verifySignature)
{ {
auto signedSize = leases - m_Buffer; auto signedSize = leases - m_Buffer;
if (signedSize + m_Identity->GetSignatureLen () > m_BufferLen) if (signedSize + m_Identity->GetSignatureLen () > m_BufferLen)
{ {
LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", m_BufferLen); LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", m_BufferLen);
m_IsValid = false; m_IsValid = false;
} }
else if (!m_Identity->Verify (m_Buffer, signedSize, leases)) else if (!m_Identity->Verify (m_Buffer, signedSize, leases))
{ {
LogPrint (eLogWarning, "LeaseSet: Verification failed"); LogPrint (eLogWarning, "LeaseSet: Verification failed");
@ -863,17 +863,17 @@ namespace data
} }
// update expiration // update expiration
if (expirationTime) if (expirationTime)
{ {
SetExpirationTime (expirationTime*1000LL); SetExpirationTime (expirationTime*1000LL);
auto expires = (int)expirationTime - timestamp; auto expires = (int)expirationTime - timestamp;
htobe16buf (expiresBuf, expires > 0 ? expires : 0); htobe16buf (expiresBuf, expires > 0 ? expires : 0);
} }
else else
{ {
// no tunnels or withdraw // no tunnels or withdraw
SetExpirationTime (timestamp*1000LL); SetExpirationTime (timestamp*1000LL);
memset (expiresBuf, 0, 2); // expires immeditely memset (expiresBuf, 0, 2); // expires immeditely
} }
// sign // sign
keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type
} }
@ -916,7 +916,7 @@ namespace data
{ {
LogPrint (eLogError, "LeaseSet2: Can't create blinded signer for signature type ", blindedKey.GetSigType ()); LogPrint (eLogError, "LeaseSet2: Can't create blinded signer for signature type ", blindedKey.GetSigType ());
return; return;
} }
auto offset = 1; auto offset = 1;
htobe16buf (m_Buffer + offset, blindedKey.GetBlindedSigType ()); offset += 2; // Blinded Public Key Sig Type htobe16buf (m_Buffer + offset, blindedKey.GetBlindedSigType ()); offset += 2; // Blinded Public Key Sig Type
memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key

View File

@ -329,7 +329,7 @@ namespace transport
m_SendSipKey (nullptr), m_ReceiveSipKey (nullptr), m_SendSipKey (nullptr), m_ReceiveSipKey (nullptr),
#endif #endif
m_NextReceivedLen (0), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), m_NextReceivedLen (0), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr),
m_NextReceivedBufferSize (0), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_NextReceivedBufferSize (0), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0),
m_IsSending (false), m_IsReceiving (false), m_NextPaddingSize (16) m_IsSending (false), m_IsReceiving (false), m_NextPaddingSize (16)
{ {
if (in_RemoteRouter) // Alice if (in_RemoteRouter) // Alice
@ -401,7 +401,7 @@ namespace transport
} }
void NTCP2Session::CreateNextReceivedBuffer (size_t size) void NTCP2Session::CreateNextReceivedBuffer (size_t size)
{ {
if (m_NextReceivedBuffer) if (m_NextReceivedBuffer)
{ {
if (size <= m_NextReceivedBufferSize) if (size <= m_NextReceivedBufferSize)
@ -411,19 +411,19 @@ namespace transport
} }
m_NextReceivedBuffer = new uint8_t[size]; m_NextReceivedBuffer = new uint8_t[size];
m_NextReceivedBufferSize = size; m_NextReceivedBufferSize = size;
} }
void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts) void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts)
{ {
if (m_NextReceivedBuffer && !m_IsReceiving && if (m_NextReceivedBuffer && !m_IsReceiving &&
ts > m_LastActivityTimestamp + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT) ts > m_LastActivityTimestamp + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
{ {
delete[] m_NextReceivedBuffer; delete[] m_NextReceivedBuffer;
m_NextReceivedBuffer = nullptr; m_NextReceivedBuffer = nullptr;
m_NextReceivedBufferSize = 0; m_NextReceivedBufferSize = 0;
} }
} }
void NTCP2Session::KeyDerivationFunctionDataPhase () void NTCP2Session::KeyDerivationFunctionDataPhase ()
{ {
uint8_t k[64]; uint8_t k[64];
@ -716,7 +716,7 @@ namespace transport
EVP_DigestSignInit (m_SendMDCtx, &ctx, nullptr, nullptr, sipKey); EVP_DigestSignInit (m_SendMDCtx, &ctx, nullptr, nullptr, sipKey);
EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr); EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr);
EVP_PKEY_free (sipKey); EVP_PKEY_free (sipKey);
sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, receiveSipKey, 16); sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, receiveSipKey, 16);
m_ReceiveMDCtx = EVP_MD_CTX_create (); m_ReceiveMDCtx = EVP_MD_CTX_create ();
ctx = nullptr; ctx = nullptr;
@ -879,11 +879,11 @@ namespace transport
auto nextMsg = (frame[offset] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPMessage (size); auto nextMsg = (frame[offset] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPMessage (size);
nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header
if (nextMsg->len <= nextMsg->maxLen) if (nextMsg->len <= nextMsg->maxLen)
{ {
memcpy (nextMsg->GetNTCP2Header (), frame + offset, size); memcpy (nextMsg->GetNTCP2Header (), frame + offset, size);
nextMsg->FromNTCP2 (); nextMsg->FromNTCP2 ();
m_Handler.PutNextMessage (std::move (nextMsg)); m_Handler.PutNextMessage (std::move (nextMsg));
} }
else else
LogPrint (eLogError, "NTCP2: I2NP block is too long for I2NP message"); LogPrint (eLogError, "NTCP2: I2NP block is too long for I2NP message");
break; break;
@ -914,7 +914,7 @@ namespace transport
EVP_DigestSignInit (m_SendMDCtx, nullptr, nullptr, nullptr, nullptr); EVP_DigestSignInit (m_SendMDCtx, nullptr, nullptr, nullptr, nullptr);
EVP_DigestSignUpdate (m_SendMDCtx, m_SendIV.buf, 8); EVP_DigestSignUpdate (m_SendMDCtx, m_SendIV.buf, 8);
size_t l = 8; size_t l = 8;
EVP_DigestSignFinal (m_SendMDCtx, m_SendIV.buf, &l); EVP_DigestSignFinal (m_SendMDCtx, m_SendIV.buf, &l);
#else #else
i2p::crypto::Siphash<8> (m_SendIV.buf, m_SendIV.buf, 8, m_SendSipKey); i2p::crypto::Siphash<8> (m_SendIV.buf, m_SendIV.buf, 8, m_SendSipKey);
#endif #endif
@ -1081,15 +1081,15 @@ namespace transport
size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100; size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100;
if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3; if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3;
if (paddingSize > len) paddingSize = len; if (paddingSize > len) paddingSize = len;
if (paddingSize) if (paddingSize)
{ {
if (m_NextPaddingSize >= 16) if (m_NextPaddingSize >= 16)
{ {
RAND_bytes ((uint8_t *)m_PaddingSizes, sizeof (m_PaddingSizes)); RAND_bytes ((uint8_t *)m_PaddingSizes, sizeof (m_PaddingSizes));
m_NextPaddingSize = 0; m_NextPaddingSize = 0;
} }
paddingSize = m_PaddingSizes[m_NextPaddingSize++] % paddingSize; paddingSize = m_PaddingSizes[m_NextPaddingSize++] % paddingSize;
} }
buf[0] = eNTCP2BlkPadding; // blk buf[0] = eNTCP2BlkPadding; // blk
htobe16buf (buf + 1, paddingSize); // size htobe16buf (buf + 1, paddingSize); // size
memset (buf + 3, 0, paddingSize); memset (buf + 3, 0, paddingSize);
@ -1120,7 +1120,7 @@ namespace transport
!m_SendMDCtx !m_SendMDCtx
#else #else
!m_SendSipKey !m_SendSipKey
#endif #endif
) return; ) return;
m_NextSendBuffer = new uint8_t[49]; // 49 = 12 bytes message + 16 bytes MAC + 2 bytes size + up to 19 padding block m_NextSendBuffer = new uint8_t[49]; // 49 = 12 bytes message + 16 bytes MAC + 2 bytes size + up to 19 padding block
// termination block // termination block

View File

@ -42,7 +42,7 @@ namespace transport
const int NTCP2_CLOCK_SKEW = 60; // in seconds const int NTCP2_CLOCK_SKEW = 60; // in seconds
const int NTCP2_MAX_OUTGOING_QUEUE_SIZE = 500; // how many messages we can queue up const int NTCP2_MAX_OUTGOING_QUEUE_SIZE = 500; // how many messages we can queue up
enum NTCP2BlockType enum NTCP2BlockType
{ {
eNTCP2BlkDateTime = 0, eNTCP2BlkDateTime = 0,
@ -118,7 +118,7 @@ namespace transport
i2p::data::IdentHash m_RemoteIdentHash; i2p::data::IdentHash m_RemoteIdentHash;
uint16_t m3p2Len; uint16_t m3p2Len;
uint8_t m_SessionRequestBuffer[NTCP2_SESSION_REQUEST_MAX_SIZE], uint8_t m_SessionRequestBuffer[NTCP2_SESSION_REQUEST_MAX_SIZE],
m_SessionCreatedBuffer[NTCP2_SESSION_CREATED_MAX_SIZE], * m_SessionConfirmedBuffer; m_SessionCreatedBuffer[NTCP2_SESSION_CREATED_MAX_SIZE], * m_SessionConfirmedBuffer;
size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen;
@ -137,7 +137,7 @@ namespace transport
void Done (); void Done ();
void Close () { m_Socket.close (); }; // for accept void Close () { m_Socket.close (); }; // for accept
void DeleteNextReceiveBuffer (uint64_t ts); void DeleteNextReceiveBuffer (uint64_t ts);
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
const boost::asio::ip::tcp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; const boost::asio::ip::tcp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
void SetRemoteEndpoint (const boost::asio::ip::tcp::endpoint& ep) { m_RemoteEndpoint = ep; }; void SetRemoteEndpoint (const boost::asio::ip::tcp::endpoint& ep) { m_RemoteEndpoint = ep; };
@ -226,7 +226,7 @@ namespace transport
uint64_t m_NextRouterInfoResendTime; // seconds since epoch uint64_t m_NextRouterInfoResendTime; // seconds since epoch
uint16_t m_PaddingSizes[16]; uint16_t m_PaddingSizes[16];
int m_NextPaddingSize; int m_NextPaddingSize;
}; };
class NTCP2Server: private i2p::util::RunnableServiceWithWork class NTCP2Server: private i2p::util::RunnableServiceWithWork
@ -258,7 +258,7 @@ namespace transport
void UseProxy(ProxyType proxy, const std::string& address, uint16_t port, const std::string& user, const std::string& pass); void UseProxy(ProxyType proxy, const std::string& address, uint16_t port, const std::string& user, const std::string& pass);
void SetLocalAddress (const boost::asio::ip::address& localAddress); void SetLocalAddress (const boost::asio::ip::address& localAddress);
private: private:
void HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error); void HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
@ -267,7 +267,7 @@ namespace transport
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer); void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer); void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer); void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
// timer // timer
void ScheduleTermination (); void ScheduleTermination ();
void HandleTerminationTimer (const boost::system::error_code& ecode); void HandleTerminationTimer (const boost::system::error_code& ecode);
@ -285,7 +285,7 @@ namespace transport
boost::asio::ip::tcp::resolver m_Resolver; boost::asio::ip::tcp::resolver m_Resolver;
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint; std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress; std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress;
public: public:
// for HTTP/I2PControl // for HTTP/I2PControl

View File

@ -56,9 +56,9 @@ namespace data
uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold); uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
if (m_RouterInfos.size () < threshold || m_Floodfills.size () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils if (m_RouterInfos.size () < threshold || m_Floodfills.size () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils
{ {
Reseed (); Reseed ();
} }
else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false)) else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false))
Reseed (); // we don't have a router we can connect to. Trying to reseed Reseed (); // we don't have a router we can connect to. Trying to reseed
@ -73,7 +73,7 @@ namespace data
m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ()); m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ());
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
m_Floodfills.push_back (i2p::context.GetSharedRouterInfo ()); m_Floodfills.push_back (i2p::context.GetSharedRouterInfo ());
i2p::config::GetOption("persist.profiles", m_PersistProfiles); i2p::config::GetOption("persist.profiles", m_PersistProfiles);
m_IsRunning = true; m_IsRunning = true;
@ -148,7 +148,7 @@ namespace data
} }
if (!m_IsRunning) break; if (!m_IsRunning) break;
if (!i2p::transport::transports.IsOnline ()) continue; // don't manage netdb when offline if (!i2p::transport::transports.IsOnline ()) continue; // don't manage netdb when offline
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts - lastManageRequest >= 15) // manage requests every 15 seconds if (ts - lastManageRequest >= 15) // manage requests every 15 seconds
{ {
@ -170,8 +170,8 @@ namespace data
lastDestinationCleanup = ts; lastDestinationCleanup = ts;
} }
// publish // publish
if (!m_HiddenMode && i2p::transport::transports.IsOnline ()) if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
{ {
bool publish = false; bool publish = false;
if (m_PublishReplyToken) if (m_PublishReplyToken)
@ -179,15 +179,15 @@ namespace data
// next publishing attempt // next publishing attempt
if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true; if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true;
} }
else if (i2p::context.GetLastUpdateTime () > lastPublish || else if (i2p::context.GetLastUpdateTime () > lastPublish ||
ts - lastPublish >= NETDB_PUBLISH_INTERVAL) ts - lastPublish >= NETDB_PUBLISH_INTERVAL)
{ {
// new publish // new publish
m_PublishExcluded.clear (); m_PublishExcluded.clear ();
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // do publish to ourselves m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // do publish to ourselves
publish = true; publish = true;
} }
if (publish) // update timestamp and publish if (publish) // update timestamp and publish
{ {
i2p::context.UpdateTimestamp (ts); i2p::context.UpdateTimestamp (ts);
@ -290,7 +290,7 @@ namespace data
if (inserted) if (inserted)
{ {
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64()); LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
if (r->IsFloodfill () && r->IsEligibleFloodfill ()) if (r->IsFloodfill () && r->IsEligibleFloodfill ())
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.push_back (r); m_Floodfills.push_back (r);
@ -476,14 +476,14 @@ namespace data
{ {
auto r = std::make_shared<RouterInfo>(path); auto r = std::make_shared<RouterInfo>(path);
if (r->GetRouterIdentity () && !r->IsUnreachable () && r->HasValidAddresses ()) if (r->GetRouterIdentity () && !r->IsUnreachable () && r->HasValidAddresses ())
{ {
r->DeleteBuffer (); r->DeleteBuffer ();
r->ClearProperties (); // properties are not used for regular routers r->ClearProperties (); // properties are not used for regular routers
if (m_RouterInfos.emplace (r->GetIdentHash (), r).second) if (m_RouterInfos.emplace (r->GetIdentHash (), r).second)
{ {
if (r->IsFloodfill () && r->IsEligibleFloodfill ()) if (r->IsFloodfill () && r->IsEligibleFloodfill ())
m_Floodfills.push_back (r); m_Floodfills.push_back (r);
} }
} }
else else
{ {
@ -591,7 +591,7 @@ namespace data
expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL : expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total; NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
auto own = i2p::context.GetSharedRouterInfo (); auto own = i2p::context.GetSharedRouterInfo ();
for (auto& it: m_RouterInfos) for (auto& it: m_RouterInfos)
{ {
if (it.second == own) continue; // skip own if (it.second == own) continue; // skip own
@ -608,8 +608,8 @@ namespace data
} }
// make router reachable back if too few routers or floodfills // make router reachable back if too few routers or floodfills
if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS ||
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS))) (it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
it.second->SetUnreachable (false); it.second->SetUnreachable (false);
// find & mark expired routers // find & mark expired routers
if (!it.second->IsReachable () && it.second->IsSSU (false)) if (!it.second->IsReachable () && it.second->IsSSU (false))
{ {
@ -626,7 +626,7 @@ namespace data
// delete RI file // delete RI file
m_Storage.Remove(ident); m_Storage.Remove(ident);
deletedCount++; deletedCount++;
if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false; if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false;
} }
} // m_RouterInfos iteration } // m_RouterInfos iteration
@ -674,7 +674,7 @@ namespace data
if (floodfill) if (floodfill)
{ {
if (direct && !floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) && if (direct && !floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) &&
!i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) !i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
direct = false; // floodfill can't be reached directly direct = false; // floodfill can't be reached directly
if (direct) if (direct)
transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
@ -688,10 +688,10 @@ namespace data
else else
{ {
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found"); LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found");
m_Requests.RequestComplete (destination, nullptr); m_Requests.RequestComplete (destination, nullptr);
} }
} }
} }
else else
{ {
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no floodfills found"); LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no floodfills found");
@ -1051,8 +1051,8 @@ namespace data
m_PublishExcluded.clear (); m_PublishExcluded.clear ();
m_PublishReplyToken = 0; m_PublishReplyToken = 0;
} }
} }
void NetDb::Explore (int numDestinations) void NetDb::Explore (int numDestinations)
{ {
// new requests // new requests
@ -1112,7 +1112,7 @@ namespace data
LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again"); LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
m_PublishExcluded.clear (); m_PublishExcluded.clear ();
} }
auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded); auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
if (floodfill) if (floodfill)
{ {
@ -1122,19 +1122,19 @@ namespace data
m_PublishExcluded.insert (floodfill->GetIdentHash ()); m_PublishExcluded.insert (floodfill->GetIdentHash ());
m_PublishReplyToken = replyToken; m_PublishReplyToken = replyToken;
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect? if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ? i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
// send directly // send directly
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken)); transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
else else
{ {
// otherwise through exploratory // otherwise through exploratory
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool (); auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr; auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr; auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
if (inbound && outbound) if (inbound && outbound)
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0,
CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound)); CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
} }
} }
} }
@ -1174,7 +1174,7 @@ namespace data
{ {
return !router->IsHidden () && router != compatibleWith && return !router->IsHidden () && router != compatibleWith &&
(reverse ? compatibleWith->IsReachableFrom (*router) : (reverse ? compatibleWith->IsReachableFrom (*router) :
router->IsReachableFrom (*compatibleWith)) && router->IsReachableFrom (*compatibleWith)) &&
router->IsECIES (); router->IsECIES ();
}); });
} }
@ -1184,7 +1184,7 @@ namespace data
return GetRandomRouter ( return GetRandomRouter (
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool [v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
{ {
return !router->IsHidden () && router->IsECIES () && return !router->IsHidden () && router->IsECIES () &&
router->IsPeerTesting (v4) && !excluded.count (router->GetIdentHash ()); router->IsPeerTesting (v4) && !excluded.count (router->GetIdentHash ());
}); });
} }
@ -1216,7 +1216,7 @@ namespace data
return !router->IsHidden () && router != compatibleWith && return !router->IsHidden () && router != compatibleWith &&
(reverse ? compatibleWith->IsReachableFrom (*router) : (reverse ? compatibleWith->IsReachableFrom (*router) :
router->IsReachableFrom (*compatibleWith)) && router->IsReachableFrom (*compatibleWith)) &&
(router->GetCaps () & RouterInfo::eHighBandwidth) && (router->GetCaps () & RouterInfo::eHighBandwidth) &&
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION && router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
router->IsECIES (); router->IsECIES ();
}); });
@ -1238,12 +1238,12 @@ namespace data
return it->second; return it->second;
// try some routers around // try some routers around
auto it1 = m_RouterInfos.begin (); auto it1 = m_RouterInfos.begin ();
if (inds[0]) if (inds[0])
{ {
// before // before
inds[1] %= inds[0]; inds[1] %= inds[0];
std::advance (it1, (inds[1] + inds[0])/2); std::advance (it1, (inds[1] + inds[0])/2);
} }
else else
it1 = it; it1 = it;
auto it2 = it; auto it2 = it;
@ -1254,7 +1254,7 @@ namespace data
std::advance (it2, inds[2]); std::advance (it2, inds[2]);
} }
// it1 - from, it2 - to // it1 - from, it2 - to
it = it1; it = it1;
while (it != it2 && it != m_RouterInfos.end ()) while (it != it2 && it != m_RouterInfos.end ())
{ {
if (!it->second->IsUnreachable () && filter (it->second)) if (!it->second->IsUnreachable () && filter (it->second))

View File

@ -43,7 +43,7 @@ namespace data
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours
const int NETDB_PUBLISH_INTERVAL = 60 * 40; const int NETDB_PUBLISH_INTERVAL = 60 * 40;
const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15; const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 36); // 0.9.36 const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 36); // 0.9.36
const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 38); // 0.9.38 const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 38); // 0.9.38
const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51

View File

@ -84,15 +84,15 @@ namespace data
{ {
bool ipv6; i2p::config::GetOption("ipv6", ipv6); bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool ipv4; i2p::config::GetOption("ipv4", ipv4);
std::vector<std::string> httpsReseedHostList; std::vector<std::string> httpsReseedHostList;
if (ipv4 || ipv6) if (ipv4 || ipv6)
{ {
std::string reseedURLs; i2p::config::GetOption("reseed.urls", reseedURLs); std::string reseedURLs; i2p::config::GetOption("reseed.urls", reseedURLs);
if (!reseedURLs.empty ()) if (!reseedURLs.empty ())
boost::split(httpsReseedHostList, reseedURLs, boost::is_any_of(","), boost::token_compress_on); boost::split(httpsReseedHostList, reseedURLs, boost::is_any_of(","), boost::token_compress_on);
} }
std::vector<std::string> yggReseedHostList; std::vector<std::string> yggReseedHostList;
if (!i2p::util::net::GetYggdrasilAddress ().is_unspecified ()) if (!i2p::util::net::GetYggdrasilAddress ().is_unspecified ())
{ {
@ -100,7 +100,7 @@ namespace data
std::string yggReseedURLs; i2p::config::GetOption("reseed.yggurls", yggReseedURLs); std::string yggReseedURLs; i2p::config::GetOption("reseed.yggurls", yggReseedURLs);
if (!yggReseedURLs.empty ()) if (!yggReseedURLs.empty ())
boost::split(yggReseedHostList, yggReseedURLs, boost::is_any_of(","), boost::token_compress_on); boost::split(yggReseedHostList, yggReseedURLs, boost::is_any_of(","), boost::token_compress_on);
} }
if (httpsReseedHostList.empty () && yggReseedHostList.empty()) if (httpsReseedHostList.empty () && yggReseedHostList.empty())
{ {
@ -113,7 +113,7 @@ namespace data
{ {
auto ind = rand () % (httpsReseedHostList.size () + yggReseedHostList.size ()); auto ind = rand () % (httpsReseedHostList.size () + yggReseedHostList.size ());
bool isHttps = ind < httpsReseedHostList.size (); bool isHttps = ind < httpsReseedHostList.size ();
std::string reseedUrl = isHttps ? httpsReseedHostList[ind] : std::string reseedUrl = isHttps ? httpsReseedHostList[ind] :
yggReseedHostList[ind - httpsReseedHostList.size ()]; yggReseedHostList[ind - httpsReseedHostList.size ()];
reseedUrl += "i2pseeds.su3"; reseedUrl += "i2pseeds.su3";
auto num = ReseedFromSU3Url (reseedUrl, isHttps); auto num = ReseedFromSU3Url (reseedUrl, isHttps);
@ -680,30 +680,30 @@ namespace data
auto it = boost::asio::ip::tcp::resolver(service).resolve ( auto it = boost::asio::ip::tcp::resolver(service).resolve (
boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode); boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode);
if (!ecode) if (!ecode)
{ {
bool connected = false; bool connected = false;
boost::asio::ip::tcp::resolver::iterator end; boost::asio::ip::tcp::resolver::iterator end;
while (it != end) while (it != end)
{ {
boost::asio::ip::tcp::endpoint ep = *it; boost::asio::ip::tcp::endpoint ep = *it;
if ((ep.address ().is_v4 () && i2p::context.SupportsV4 ()) || if ((ep.address ().is_v4 () && i2p::context.SupportsV4 ()) ||
(ep.address ().is_v6 () && i2p::context.SupportsV6 ())) (ep.address ().is_v6 () && i2p::context.SupportsV6 ()))
{ {
s.lowest_layer().connect (ep, ecode); s.lowest_layer().connect (ep, ecode);
if (!ecode) if (!ecode)
{ {
connected = true; connected = true;
break; break;
} }
} }
it++; it++;
} }
if (!connected) if (!connected)
{ {
LogPrint(eLogError, "Reseed: Failed to connect to ", url.host); LogPrint(eLogError, "Reseed: Failed to connect to ", url.host);
return ""; return "";
} }
} }
} }
if (!ecode) if (!ecode)
{ {
@ -762,12 +762,12 @@ namespace data
data = out.str(); data = out.str();
} }
return data; return data;
} }
std::string Reseeder::YggdrasilRequest (const std::string& address) std::string Reseeder::YggdrasilRequest (const std::string& address)
{ {
i2p::http::URL url; i2p::http::URL url;
if (!url.parse(address)) if (!url.parse(address))
{ {
LogPrint(eLogError, "Reseed: Failed to parse url: ", address); LogPrint(eLogError, "Reseed: Failed to parse url: ", address);
return ""; return "";
@ -776,7 +776,7 @@ namespace data
if (!url.port) url.port = 80; if (!url.port) url.port = 80;
boost::system::error_code ecode; boost::system::error_code ecode;
boost::asio::io_service service; boost::asio::io_service service;
boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6()); boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6());
if (url.host.length () < 2) return ""; // assume [] if (url.host.length () < 2) return ""; // assume []
@ -789,9 +789,9 @@ namespace data
return ReseedRequest (s, url.to_string()); return ReseedRequest (s, url.to_string());
} }
else else
LogPrint (eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message ()); LogPrint (eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message ());
return ""; return "";
} }
} }
} }

View File

@ -49,8 +49,8 @@ namespace data
std::string HttpsRequest (const std::string& address); std::string HttpsRequest (const std::string& address);
std::string YggdrasilRequest (const std::string& address); std::string YggdrasilRequest (const std::string& address);
template<typename Stream> template<typename Stream>
std::string ReseedRequest (Stream& s, const std::string& uri); std::string ReseedRequest (Stream& s, const std::string& uri);
private: private:
std::map<std::string, PublicKey> m_SigningKeys; std::map<std::string, PublicKey> m_SigningKeys;

View File

@ -566,10 +566,10 @@ namespace i2p
{ {
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published); bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
if (ntcp2) if (ntcp2)
{ {
if (ntcp2Published) if (ntcp2Published)
{ {
std::string ntcp2Host; std::string ntcp2Host;
if (!i2p::config::IsDefault ("ntcp2.addressv6")) if (!i2p::config::IsDefault ("ntcp2.addressv6"))
i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host); i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host);
@ -578,7 +578,7 @@ namespace i2p
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port); uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
if (!ntcp2Port) ntcp2Port = port; if (!ntcp2Port) ntcp2Port = port;
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (ntcp2Host), ntcp2Port); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (ntcp2Host), ntcp2Port);
} }
else else
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV6); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV6);
} }
@ -839,13 +839,13 @@ namespace i2p
} }
buf += 4; buf += 4;
if (!HandleECIESx25519TagMessage (buf, len)) // try tag first if (!HandleECIESx25519TagMessage (buf, len)) // try tag first
{ {
// then Noise_N one-time decryption // then Noise_N one-time decryption
if (m_ECIESSession) if (m_ECIESSession)
m_ECIESSession->HandleNextMessage (buf, len); m_ECIESSession->HandleNextMessage (buf, len);
else else
LogPrint (eLogError, "Router: Session is not set for ECIES router"); LogPrint (eLogError, "Router: Session is not set for ECIES router");
} }
} }
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg) void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
@ -881,7 +881,7 @@ namespace i2p
} }
bool RouterContext::DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize) bool RouterContext::DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize)
{ {
// m_InitialNoiseState is h = SHA256(h || hepk) // m_InitialNoiseState is h = SHA256(h || hepk)
m_CurrentNoiseState = m_InitialNoiseState; m_CurrentNoiseState = m_InitialNoiseState;
m_CurrentNoiseState.MixHash (encrypted, 32); // h = SHA256(h || sepk) m_CurrentNoiseState.MixHash (encrypted, 32); // h = SHA256(h || sepk)
@ -895,7 +895,7 @@ namespace i2p
encrypted += 32; encrypted += 32;
uint8_t nonce[12]; uint8_t nonce[12];
memset (nonce, 0, 12); memset (nonce, 0, 12);
if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, clearTextSize, m_CurrentNoiseState.m_H, 32, if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, clearTextSize, m_CurrentNoiseState.m_H, 32,
m_CurrentNoiseState.m_CK + 32, nonce, data, clearTextSize, false)) // decrypt m_CurrentNoiseState.m_CK + 32, nonce, data, clearTextSize, false)) // decrypt
{ {
LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed"); LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed");
@ -908,8 +908,8 @@ namespace i2p
bool RouterContext::DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data) bool RouterContext::DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data)
{ {
return DecryptECIESTunnelBuildRecord (encrypted, data, SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE); return DecryptECIESTunnelBuildRecord (encrypted, data, SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE);
} }
i2p::crypto::X25519Keys& RouterContext::GetStaticKeys () i2p::crypto::X25519Keys& RouterContext::GetStaticKeys ()
{ {
if (!m_StaticKeys) if (!m_StaticKeys)

View File

@ -67,7 +67,7 @@ namespace garlic
void Init (); void Init ();
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; }; i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; };
std::shared_ptr<i2p::data::RouterInfo> GetSharedRouterInfo () std::shared_ptr<i2p::data::RouterInfo> GetSharedRouterInfo ()
{ {
return std::shared_ptr<i2p::data::RouterInfo> (&m_RouterInfo, return std::shared_ptr<i2p::data::RouterInfo> (&m_RouterInfo,
@ -97,7 +97,7 @@ namespace garlic
void SetNetID (int netID) { m_NetID = netID; }; void SetNetID (int netID) { m_NetID = netID; };
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data); bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data);
bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data); bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data);
void UpdatePort (int port); // called from Daemon void UpdatePort (int port); // called from Daemon
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg); void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg);
@ -160,7 +160,7 @@ namespace garlic
void SaveKeys (); void SaveKeys ();
bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize); bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize);
private: private:
i2p::data::RouterInfo m_RouterInfo; i2p::data::RouterInfo m_RouterInfo;

View File

@ -194,7 +194,7 @@ namespace data
// read addresses // read addresses
auto addresses = boost::make_shared<Addresses>(); auto addresses = boost::make_shared<Addresses>();
uint8_t numAddresses; uint8_t numAddresses;
s.read ((char *)&numAddresses, sizeof (numAddresses)); s.read ((char *)&numAddresses, sizeof (numAddresses));
addresses->reserve (numAddresses); addresses->reserve (numAddresses);
for (int i = 0; i < numAddresses; i++) for (int i = 0; i < numAddresses; i++)
{ {
@ -207,10 +207,10 @@ namespace data
char transportStyle[6]; char transportStyle[6];
ReadString (transportStyle, 6, s); ReadString (transportStyle, 6, s);
if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2 if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2
{ {
address->transportStyle = eTransportNTCP; address->transportStyle = eTransportNTCP;
address->ntcp2.reset (new NTCP2Ext ()); address->ntcp2.reset (new NTCP2Ext ());
} }
else if (!strcmp (transportStyle, "SSU")) else if (!strcmp (transportStyle, "SSU"))
{ {
address->transportStyle = eTransportSSU; address->transportStyle = eTransportSSU;
@ -283,11 +283,11 @@ namespace data
if (s) continue; else return; if (s) continue; else return;
} }
if (index >= address->ssu->introducers.size ()) if (index >= address->ssu->introducers.size ())
{ {
if (address->ssu->introducers.empty ()) // first time if (address->ssu->introducers.empty ()) // first time
address->ssu->introducers.reserve (3); address->ssu->introducers.reserve (3);
address->ssu->introducers.resize (index + 1); address->ssu->introducers.resize (index + 1);
} }
Introducer& introducer = address->ssu->introducers.at (index); Introducer& introducer = address->ssu->introducers.at (index);
if (!strcmp (key, "ihost")) if (!strcmp (key, "ihost"))
{ {
@ -308,39 +308,39 @@ namespace data
if (address->transportStyle == eTransportNTCP) if (address->transportStyle == eTransportNTCP)
{ {
if (isStaticKey) if (isStaticKey)
{ {
if (isHost) if (isHost)
{ {
if (address->host.is_v6 ()) if (address->host.is_v6 ())
supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6); supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
else else
supportedTransports |= eNTCP2V4; supportedTransports |= eNTCP2V4;
m_ReachableTransports |= supportedTransports; m_ReachableTransports |= supportedTransports;
} }
else if (!address->published) else if (!address->published)
{ {
if (address->caps) if (address->caps)
{ {
if (address->caps & AddressCaps::eV4) supportedTransports |= eNTCP2V4; if (address->caps & AddressCaps::eV4) supportedTransports |= eNTCP2V4;
if (address->caps & AddressCaps::eV6) supportedTransports |= eNTCP2V6; if (address->caps & AddressCaps::eV6) supportedTransports |= eNTCP2V6;
} }
else else
supportedTransports |= eNTCP2V4; // most likely, since we don't have host supportedTransports |= eNTCP2V4; // most likely, since we don't have host
} }
} }
} }
else if (address->transportStyle == eTransportSSU) else if (address->transportStyle == eTransportSSU)
{ {
if (isIntroKey) if (isIntroKey)
{ {
if (isHost) if (isHost)
supportedTransports |= address->host.is_v4 () ? eSSUV4 : eSSUV6; supportedTransports |= address->host.is_v4 () ? eSSUV4 : eSSUV6;
else if (address->caps & AddressCaps::eV6) else if (address->caps & AddressCaps::eV6)
{ {
supportedTransports |= eSSUV6; supportedTransports |= eSSUV6;
if (address->caps & AddressCaps::eV4) supportedTransports |= eSSUV4; // in additional to v6 if (address->caps & AddressCaps::eV4) supportedTransports |= eSSUV4; // in additional to v6
} }
else else
supportedTransports |= eSSUV4; // in case if host or 6 caps is not preasented, we assume 4 supportedTransports |= eSSUV4; // in case if host or 6 caps is not preasented, we assume 4
if (address->ssu && !address->ssu->introducers.empty ()) if (address->ssu && !address->ssu->introducers.empty ())
{ {
@ -350,24 +350,24 @@ namespace data
for (auto& it: address->ssu->introducers) for (auto& it: address->ssu->introducers)
{ {
if (!it.iExp) it.iExp = m_Timestamp/1000 + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT; if (!it.iExp) it.iExp = m_Timestamp/1000 + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT;
if (ts <= it.iExp && it.iPort > 0 && if (ts <= it.iExp && it.iPort > 0 &&
((it.iHost.is_v4 () && address->IsV4 ()) || (it.iHost.is_v6 () && address->IsV6 ()))) ((it.iHost.is_v4 () && address->IsV4 ()) || (it.iHost.is_v6 () && address->IsV6 ())))
numValid++; numValid++;
else else
it.iPort = 0; it.iPort = 0;
} }
if (numValid) if (numValid)
m_ReachableTransports |= supportedTransports; m_ReachableTransports |= supportedTransports;
else else
address->ssu->introducers.resize (0); address->ssu->introducers.resize (0);
} }
else if (isHost && address->port) else if (isHost && address->port)
{ {
address->published = true; address->published = true;
m_ReachableTransports |= supportedTransports; m_ReachableTransports |= supportedTransports;
} }
} }
} }
if (supportedTransports) if (supportedTransports)
{ {
addresses->push_back(address); addresses->push_back(address);
@ -492,10 +492,10 @@ namespace data
{ {
case CAPS_FLAG_V4: case CAPS_FLAG_V4:
caps |= AddressCaps::eV4; caps |= AddressCaps::eV4;
break; break;
case CAPS_FLAG_V6: case CAPS_FLAG_V6:
caps |= AddressCaps::eV6; caps |= AddressCaps::eV6;
break; break;
case CAPS_FLAG_SSU_TESTING: case CAPS_FLAG_SSU_TESTING:
caps |= AddressCaps::eSSUTesting; caps |= AddressCaps::eSSUTesting;
break; break;
@ -508,7 +508,7 @@ namespace data
} }
return caps; return caps;
} }
void RouterInfo::UpdateCapsProperty () void RouterInfo::UpdateCapsProperty ()
{ {
std::string caps; std::string caps;
@ -559,7 +559,7 @@ namespace data
if (address.transportStyle == eTransportNTCP) if (address.transportStyle == eTransportNTCP)
{ {
if (address.IsNTCP2 ()) if (address.IsNTCP2 ())
{ {
WriteString ("NTCP2", s); WriteString ("NTCP2", s);
if (address.IsPublishedNTCP2 () && !address.host.is_unspecified () && address.port) if (address.IsPublishedNTCP2 () && !address.host.is_unspecified () && address.port)
isPublished = true; isPublished = true;
@ -573,45 +573,45 @@ namespace data
if (caps.empty ()) caps += CAPS_FLAG_V4; if (caps.empty ()) caps += CAPS_FLAG_V4;
WriteString (caps, properties); WriteString (caps, properties);
properties << ';'; properties << ';';
} }
} }
else else
continue; // don't write NTCP address continue; // don't write NTCP address
} }
else if (address.transportStyle == eTransportSSU) else if (address.transportStyle == eTransportSSU)
{ {
WriteString ("SSU", s); WriteString ("SSU", s);
// caps // caps
WriteString ("caps", properties); WriteString ("caps", properties);
properties << '='; properties << '=';
std::string caps; std::string caps;
if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING; if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING;
if (address.host.is_v4 ()) if (address.host.is_v4 ())
{ {
if (address.published) if (address.published)
{ {
isPublished = true; isPublished = true;
if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER; if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
} }
else else
caps += CAPS_FLAG_V4; caps += CAPS_FLAG_V4;
} }
else if (address.host.is_v6 ()) else if (address.host.is_v6 ())
{ {
if (address.published) if (address.published)
{ {
isPublished = true; isPublished = true;
if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER; if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
} }
else else
caps += CAPS_FLAG_V6; caps += CAPS_FLAG_V6;
} }
else else
{ {
if (address.IsV4 ()) caps += CAPS_FLAG_V4; if (address.IsV4 ()) caps += CAPS_FLAG_V4;
if (address.IsV6 ()) caps += CAPS_FLAG_V6; if (address.IsV6 ()) caps += CAPS_FLAG_V6;
if (caps.empty ()) caps += CAPS_FLAG_V4; if (caps.empty ()) caps += CAPS_FLAG_V4;
} }
WriteString (caps, properties); WriteString (caps, properties);
properties << ';'; properties << ';';
} }
@ -789,7 +789,7 @@ namespace data
bool RouterInfo::SaveToFile (const std::string& fullPath) bool RouterInfo::SaveToFile (const std::string& fullPath)
{ {
if (!m_Buffer) if (!m_Buffer)
{ {
LogPrint (eLogError, "RouterInfo: Can't save, m_Buffer == NULL"); LogPrint (eLogError, "RouterInfo: Can't save, m_Buffer == NULL");
return false; return false;
@ -851,13 +851,13 @@ namespace data
m_Addresses->push_back(std::move(addr)); m_Addresses->push_back(std::move(addr));
} }
void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv, void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
const boost::asio::ip::address& host, int port, uint8_t caps) const boost::asio::ip::address& host, int port, uint8_t caps)
{ {
auto addr = std::make_shared<Address>(); auto addr = std::make_shared<Address>();
addr->host = host; addr->host = host;
addr->port = port; addr->port = port;
addr->transportStyle = eTransportNTCP; addr->transportStyle = eTransportNTCP;
addr->caps = caps; addr->caps = caps;
addr->date = 0; addr->date = 0;
addr->ntcp2.reset (new NTCP2Ext ()); addr->ntcp2.reset (new NTCP2Ext ());
@ -868,12 +868,12 @@ namespace data
{ {
m_SupportedTransports |= eNTCP2V4; m_SupportedTransports |= eNTCP2V4;
if (addr->published) m_ReachableTransports |= eNTCP2V4; if (addr->published) m_ReachableTransports |= eNTCP2V4;
} }
if (addr->IsV6 ()) if (addr->IsV6 ())
{ {
m_SupportedTransports |= eNTCP2V6; m_SupportedTransports |= eNTCP2V6;
if (addr->published) m_ReachableTransports |= eNTCP2V6; if (addr->published) m_ReachableTransports |= eNTCP2V6;
} }
m_Addresses->push_back(std::move(addr)); m_Addresses->push_back(std::move(addr));
} }
@ -881,7 +881,7 @@ namespace data
{ {
for (auto& addr : *m_Addresses) for (auto& addr : *m_Addresses)
{ {
if (addr->transportStyle == eTransportSSU && if (addr->transportStyle == eTransportSSU &&
((addr->IsV4 () && introducer.iHost.is_v4 ()) || (addr->IsV6 () && introducer.iHost.is_v6 ()))) ((addr->IsV4 () && introducer.iHost.is_v4 ()) || (addr->IsV6 () && introducer.iHost.is_v6 ())))
{ {
for (auto& intro: addr->ssu->introducers) for (auto& intro: addr->ssu->introducers)
@ -898,7 +898,7 @@ namespace data
{ {
for (auto& addr: *m_Addresses) for (auto& addr: *m_Addresses)
{ {
if (addr->transportStyle == eTransportSSU && if (addr->transportStyle == eTransportSSU &&
((addr->IsV4 () && e.address ().is_v4 ()) || (addr->IsV6 () && e.address ().is_v6 ()))) ((addr->IsV4 () && e.address ().is_v4 ()) || (addr->IsV6 () && e.address ().is_v6 ())))
{ {
for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it) for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
@ -969,8 +969,8 @@ namespace data
bool RouterInfo::IsNTCP2V6 () const bool RouterInfo::IsNTCP2V6 () const
{ {
return m_SupportedTransports & eNTCP2V6; return m_SupportedTransports & eNTCP2V6;
} }
bool RouterInfo::IsV6 () const bool RouterInfo::IsV6 () const
{ {
return m_SupportedTransports & (eSSUV6 | eNTCP2V6); return m_SupportedTransports & (eSSUV6 | eNTCP2V6);
@ -984,28 +984,28 @@ namespace data
bool RouterInfo::IsMesh () const bool RouterInfo::IsMesh () const
{ {
return m_SupportedTransports & eNTCP2V6Mesh; return m_SupportedTransports & eNTCP2V6Mesh;
} }
void RouterInfo::EnableV6 () void RouterInfo::EnableV6 ()
{ {
if (!IsV6 ()) if (!IsV6 ())
{ {
uint8_t addressCaps = AddressCaps::eV6; uint8_t addressCaps = AddressCaps::eV6;
if (IsV4 ()) addressCaps |= AddressCaps::eV4; if (IsV4 ()) addressCaps |= AddressCaps::eV4;
SetUnreachableAddressesTransportCaps (addressCaps); SetUnreachableAddressesTransportCaps (addressCaps);
UpdateSupportedTransports (); UpdateSupportedTransports ();
} }
} }
void RouterInfo::EnableV4 () void RouterInfo::EnableV4 ()
{ {
if (!IsV4 ()) if (!IsV4 ())
{ {
uint8_t addressCaps = AddressCaps::eV4; uint8_t addressCaps = AddressCaps::eV4;
if (IsV6 ()) addressCaps |= AddressCaps::eV6; if (IsV6 ()) addressCaps |= AddressCaps::eV6;
SetUnreachableAddressesTransportCaps (addressCaps); SetUnreachableAddressesTransportCaps (addressCaps);
UpdateSupportedTransports (); UpdateSupportedTransports ();
} }
} }
@ -1017,15 +1017,15 @@ namespace data
{ {
auto addr = *it; auto addr = *it;
if (addr->IsV6 ()) if (addr->IsV6 ())
{ {
if (addr->IsV4 ()) if (addr->IsV4 ())
{ {
addr->caps &= ~AddressCaps::eV6; addr->caps &= ~AddressCaps::eV6;
++it; ++it;
} }
else else
it = m_Addresses->erase (it); it = m_Addresses->erase (it);
} }
else else
++it; ++it;
} }
@ -1041,15 +1041,15 @@ namespace data
{ {
auto addr = *it; auto addr = *it;
if (addr->IsV4 ()) if (addr->IsV4 ())
{ {
if (addr->IsV6 ()) if (addr->IsV6 ())
{ {
addr->caps &= ~AddressCaps::eV4; addr->caps &= ~AddressCaps::eV4;
++it; ++it;
} }
else else
it = m_Addresses->erase (it); it = m_Addresses->erase (it);
} }
else else
++it; ++it;
} }
@ -1060,14 +1060,14 @@ namespace data
void RouterInfo::EnableMesh () void RouterInfo::EnableMesh ()
{ {
if (!IsMesh ()) if (!IsMesh ())
{ {
m_SupportedTransports |= eNTCP2V6Mesh; m_SupportedTransports |= eNTCP2V6Mesh;
m_ReachableTransports |= eNTCP2V6Mesh; m_ReachableTransports |= eNTCP2V6Mesh;
} }
} }
void RouterInfo::DisableMesh () void RouterInfo::DisableMesh ()
{ {
if (IsMesh ()) if (IsMesh ())
{ {
m_SupportedTransports &= ~eNTCP2V6Mesh; m_SupportedTransports &= ~eNTCP2V6Mesh;
@ -1080,8 +1080,8 @@ namespace data
else else
++it; ++it;
} }
} }
} }
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUAddress (bool v4only) const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUAddress (bool v4only) const
{ {
@ -1121,7 +1121,7 @@ namespace data
if (!key) return nullptr; if (!key) return nullptr;
return GetAddress ( return GetAddress (
[key](std::shared_ptr<const RouterInfo::Address> address)->bool [key](std::shared_ptr<const RouterInfo::Address> address)->bool
{ {
return address->IsNTCP2 () && !memcmp (address->ntcp2->staticKey, key, 32); return address->IsNTCP2 () && !memcmp (address->ntcp2->staticKey, key, 32);
}); });
} }
@ -1134,16 +1134,16 @@ namespace data
return address->IsPublishedNTCP2 () && address->host.is_v4 (); return address->IsPublishedNTCP2 () && address->host.is_v4 ();
}); });
} }
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V6Address () const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V6Address () const
{ {
return GetAddress ( return GetAddress (
[](std::shared_ptr<const RouterInfo::Address> address)->bool [](std::shared_ptr<const RouterInfo::Address> address)->bool
{ {
return address->IsPublishedNTCP2 () && address->host.is_v6 () && return address->IsPublishedNTCP2 () && address->host.is_v6 () &&
!i2p::util::net::IsYggdrasilAddress (address->host); !i2p::util::net::IsYggdrasilAddress (address->host);
}); });
} }
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetYggdrasilAddress () const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetYggdrasilAddress () const
{ {
@ -1152,8 +1152,8 @@ namespace data
{ {
return address->IsPublishedNTCP2 () && i2p::util::net::IsYggdrasilAddress (address->host); return address->IsPublishedNTCP2 () && i2p::util::net::IsYggdrasilAddress (address->host);
}); });
} }
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
{ {
if (!m_Profile) if (!m_Profile)
@ -1168,34 +1168,34 @@ namespace data
encryptor->Encrypt (data, encrypted); encryptor->Encrypt (data, encrypted);
} }
bool RouterInfo::IsEligibleFloodfill () const bool RouterInfo::IsEligibleFloodfill () const
{ {
// floodfill must be reachable by ipv4, >= 0.9.38 and not DSA // floodfill must be reachable by ipv4, >= 0.9.38 and not DSA
return IsReachableBy (eNTCP2V4 | eSSUV4) && m_Version >= NETDB_MIN_FLOODFILL_VERSION && return IsReachableBy (eNTCP2V4 | eSSUV4) && m_Version >= NETDB_MIN_FLOODFILL_VERSION &&
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1; GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
} }
bool RouterInfo::IsPeerTesting (bool v4) const bool RouterInfo::IsPeerTesting (bool v4) const
{ {
if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false; if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false;
return (bool)GetAddress ( return (bool)GetAddress (
[v4](std::shared_ptr<const RouterInfo::Address> address)->bool [v4](std::shared_ptr<const RouterInfo::Address> address)->bool
{ {
return (address->transportStyle == eTransportSSU) && address->IsPeerTesting () && return (address->transportStyle == eTransportSSU) && address->IsPeerTesting () &&
((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && address->IsReachableSSU (); ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && address->IsReachableSSU ();
}); });
} }
bool RouterInfo::IsIntroducer (bool v4) const bool RouterInfo::IsIntroducer (bool v4) const
{ {
if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false; if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false;
return (bool)GetAddress ( return (bool)GetAddress (
[v4](std::shared_ptr<const RouterInfo::Address> address)->bool [v4](std::shared_ptr<const RouterInfo::Address> address)->bool
{ {
return (address->transportStyle == eTransportSSU) && address->IsIntroducer () && return (address->transportStyle == eTransportSSU) && address->IsIntroducer () &&
((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified (); ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && !address->host.is_unspecified ();
}); });
} }
void RouterInfo::SetUnreachableAddressesTransportCaps (uint8_t transports) void RouterInfo::SetUnreachableAddressesTransportCaps (uint8_t transports)
{ {
@ -1220,7 +1220,7 @@ namespace data
if (addr->transportStyle == eTransportNTCP) if (addr->transportStyle == eTransportNTCP)
{ {
if (addr->IsV4 ()) transports |= eNTCP2V4; if (addr->IsV4 ()) transports |= eNTCP2V4;
if (addr->IsV6 ()) if (addr->IsV6 ())
transports |= (i2p::util::net::IsYggdrasilAddress (addr->host) ? eNTCP2V6Mesh : eNTCP2V6); transports |= (i2p::util::net::IsYggdrasilAddress (addr->host) ? eNTCP2V6Mesh : eNTCP2V6);
if (addr->IsPublishedNTCP2 ()) if (addr->IsPublishedNTCP2 ())
m_ReachableTransports |= transports; m_ReachableTransports |= transports;
@ -1231,9 +1231,9 @@ namespace data
if (addr->IsV6 ()) transports |= eSSUV6; if (addr->IsV6 ()) transports |= eSSUV6;
if (addr->IsReachableSSU ()) if (addr->IsReachableSSU ())
m_ReachableTransports |= transports; m_ReachableTransports |= transports;
} }
m_SupportedTransports |= transports; m_SupportedTransports |= transports;
} }
} }
} }
} }

View File

@ -52,7 +52,7 @@ namespace data
const uint8_t COST_NTCP2_NON_PUBLISHED = 14; const uint8_t COST_NTCP2_NON_PUBLISHED = 14;
const uint8_t COST_SSU_DIRECT = 9; const uint8_t COST_SSU_DIRECT = 9;
const uint8_t COST_SSU_THROUGH_INTRODUCERS = 11; const uint8_t COST_SSU_THROUGH_INTRODUCERS = 11;
const int MAX_RI_BUFFER_SIZE = 2048; // if RouterInfo exceeds 2048 we consider it as malformed, might be changed later const int MAX_RI_BUFFER_SIZE = 2048; // if RouterInfo exceeds 2048 we consider it as malformed, might be changed later
class RouterInfo: public RoutingDestination class RouterInfo: public RoutingDestination
{ {
@ -68,7 +68,7 @@ namespace data
eAllTransports = 0xFF eAllTransports = 0xFF
}; };
typedef uint8_t CompatibleTransports; typedef uint8_t CompatibleTransports;
enum Caps enum Caps
{ {
eFloodfill = 0x01, eFloodfill = 0x01,
@ -86,7 +86,7 @@ namespace data
eSSUTesting = 0x04, eSSUTesting = 0x04,
eSSUIntroducer = 0x08 eSSUIntroducer = 0x08
}; };
enum TransportStyle enum TransportStyle
{ {
eTransportUnknown = 0, eTransportUnknown = 0,
@ -150,7 +150,7 @@ namespace data
bool IsPublishedNTCP2 () const { return IsNTCP2 () && published; }; bool IsPublishedNTCP2 () const { return IsNTCP2 () && published; };
bool IsReachableSSU () const { return (bool)ssu && (published || !ssu->introducers.empty ()); }; bool IsReachableSSU () const { return (bool)ssu && (published || !ssu->introducers.empty ()); };
bool UsesIntroducer () const { return (bool)ssu && !ssu->introducers.empty (); }; bool UsesIntroducer () const { return (bool)ssu && !ssu->introducers.empty (); };
bool IsIntroducer () const { return caps & eSSUIntroducer; }; bool IsIntroducer () const { return caps & eSSUIntroducer; };
bool IsPeerTesting () const { return caps & eSSUTesting; }; bool IsPeerTesting () const { return caps & eSSUTesting; };
@ -173,14 +173,14 @@ namespace data
int GetVersion () const { return m_Version; }; int GetVersion () const { return m_Version; };
Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr
std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey (const uint8_t * key) const; std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey (const uint8_t * key) const;
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const; std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const; std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const; std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
std::shared_ptr<const Address> GetSSUV6Address () const; std::shared_ptr<const Address> GetSSUV6Address () const;
std::shared_ptr<const Address> GetYggdrasilAddress () const; std::shared_ptr<const Address> GetYggdrasilAddress () const;
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0); void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv, void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0); const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0);
bool AddIntroducer (const Introducer& introducer); bool AddIntroducer (const Introducer& introducer);
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
@ -196,28 +196,28 @@ namespace data
bool IsSSU (bool v4only = true) const; bool IsSSU (bool v4only = true) const;
bool IsSSUV6 () const; bool IsSSUV6 () const;
bool IsNTCP2 (bool v4only = true) const; bool IsNTCP2 (bool v4only = true) const;
bool IsNTCP2V6 () const; bool IsNTCP2V6 () const;
bool IsV6 () const; bool IsV6 () const;
bool IsV4 () const; bool IsV4 () const;
bool IsMesh () const; bool IsMesh () const;
void EnableV6 (); void EnableV6 ();
void DisableV6 (); void DisableV6 ();
void EnableV4 (); void EnableV4 ();
void DisableV4 (); void DisableV4 ();
void EnableMesh (); void EnableMesh ();
void DisableMesh (); void DisableMesh ();
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
bool IsReachableFrom (const RouterInfo& other) const { return m_ReachableTransports & other.m_SupportedTransports; }; bool IsReachableFrom (const RouterInfo& other) const { return m_ReachableTransports & other.m_SupportedTransports; };
bool IsReachableBy (CompatibleTransports transports) const { return m_ReachableTransports & transports; }; bool IsReachableBy (CompatibleTransports transports) const { return m_ReachableTransports & transports; };
CompatibleTransports GetCompatibleTransports (bool incoming) const { return incoming ? m_ReachableTransports : m_SupportedTransports; }; CompatibleTransports GetCompatibleTransports (bool incoming) const { return incoming ? m_ReachableTransports : m_SupportedTransports; };
bool HasValidAddresses () const { return m_SupportedTransports; }; bool HasValidAddresses () const { return m_SupportedTransports; };
bool IsHidden () const { return m_Caps & eHidden; }; bool IsHidden () const { return m_Caps & eHidden; };
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; }; bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; }; bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
bool IsEligibleFloodfill () const; bool IsEligibleFloodfill () const;
bool IsPeerTesting (bool v4) const; bool IsPeerTesting (bool v4) const;
bool IsIntroducer (bool v4) const; bool IsIntroducer (bool v4) const;
uint8_t GetCaps () const { return m_Caps; }; uint8_t GetCaps () const { return m_Caps; };
void SetCaps (uint8_t caps); void SetCaps (uint8_t caps);
void SetCaps (const char * caps); void SetCaps (const char * caps);

View File

@ -923,7 +923,7 @@ namespace transport
m_FragmentsPool.CleanUp (); m_FragmentsPool.CleanUp ();
m_IncompleteMessagesPool.CleanUp (); m_IncompleteMessagesPool.CleanUp ();
m_SentMessagesPool.CleanUp (); m_SentMessagesPool.CleanUp ();
SchedulePeerTestsCleanupTimer (); SchedulePeerTestsCleanupTimer ();
} }
} }

View File

@ -67,17 +67,17 @@ namespace transport
i2p::util::MemoryPool<Fragment>& GetFragmentsPool () { return m_FragmentsPool; }; i2p::util::MemoryPool<Fragment>& GetFragmentsPool () { return m_FragmentsPool; };
i2p::util::MemoryPool<IncompleteMessage>& GetIncompleteMessagesPool () { return m_IncompleteMessagesPool; }; i2p::util::MemoryPool<IncompleteMessage>& GetIncompleteMessagesPool () { return m_IncompleteMessagesPool; };
i2p::util::MemoryPool<SentMessage>& GetSentMessagesPool () { return m_SentMessagesPool; }; i2p::util::MemoryPool<SentMessage>& GetSentMessagesPool () { return m_SentMessagesPool; };
uint16_t GetPort () const { return m_Endpoint.port (); }; uint16_t GetPort () const { return m_Endpoint.port (); };
void SetLocalAddress (const boost::asio::ip::address& localAddress); void SetLocalAddress (const boost::asio::ip::address& localAddress);
void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
void AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay); void AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay);
void RemoveRelay (uint32_t tag); void RemoveRelay (uint32_t tag);
std::shared_ptr<SSUSession> FindRelaySession (uint32_t tag); std::shared_ptr<SSUSession> FindRelaySession (uint32_t tag);
void RescheduleIntroducersUpdateTimer (); void RescheduleIntroducersUpdateTimer ();
void RescheduleIntroducersUpdateTimerV6 (); void RescheduleIntroducersUpdateTimerV6 ();
void NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session = nullptr); void NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session = nullptr);
PeerTestParticipant GetPeerTestParticipant (uint32_t nonce); PeerTestParticipant GetPeerTestParticipant (uint32_t nonce);
std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce); std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce);
@ -98,7 +98,7 @@ namespace transport
void HandleReceivedPackets (std::vector<SSUPacket *> packets, void HandleReceivedPackets (std::vector<SSUPacket *> packets,
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions); std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions);
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false); std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
template<typename Filter> template<typename Filter>
std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter); std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
@ -134,7 +134,7 @@ namespace transport
boost::asio::io_service::work m_Work, m_ReceiversWork, m_ReceiversWorkV6; boost::asio::io_service::work m_Work, m_ReceiversWork, m_ReceiversWorkV6;
boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6; boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
boost::asio::ip::udp::socket m_Socket, m_SocketV6; boost::asio::ip::udp::socket m_Socket, m_SocketV6;
boost::asio::deadline_timer m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6, boost::asio::deadline_timer m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6,
m_PeerTestsCleanupTimer, m_TerminationTimer, m_TerminationTimerV6; m_PeerTestsCleanupTimer, m_TerminationTimer, m_TerminationTimerV6;
std::list<boost::asio::ip::udp::endpoint> m_Introducers, m_IntroducersV6; // introducers we are connected to std::list<boost::asio::ip::udp::endpoint> m_Introducers, m_IntroducersV6; // introducers we are connected to
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions, m_SessionsV6; std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions, m_SessionsV6;
@ -145,7 +145,7 @@ namespace transport
i2p::util::MemoryPool<IncompleteMessage> m_IncompleteMessagesPool; i2p::util::MemoryPool<IncompleteMessage> m_IncompleteMessagesPool;
i2p::util::MemoryPool<SentMessage> m_SentMessagesPool; i2p::util::MemoryPool<SentMessage> m_SentMessagesPool;
i2p::util::MemoryPoolMt<SSUPacket> m_PacketsPool; i2p::util::MemoryPoolMt<SSUPacket> m_PacketsPool;
public: public:
// for HTTP only // for HTTP only
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; }; const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };

View File

@ -188,7 +188,7 @@ namespace transport
incompleteMessage->receivedFragmentsBits |= (uint64_t(0x01) << fragmentNum); incompleteMessage->receivedFragmentsBits |= (uint64_t(0x01) << fragmentNum);
else else
LogPrint (eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64"); LogPrint (eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64");
// handle current fragment // handle current fragment
if (fragmentNum == incompleteMessage->nextFragmentNum) if (fragmentNum == incompleteMessage->nextFragmentNum)
{ {
@ -223,7 +223,7 @@ namespace transport
// missing fragment // missing fragment
LogPrint (eLogWarning, "SSU: Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID); LogPrint (eLogWarning, "SSU: Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
auto savedFragment = m_Session.GetServer ().GetFragmentsPool ().AcquireShared (fragmentNum, buf, fragmentSize, isLast); auto savedFragment = m_Session.GetServer ().GetFragmentsPool ().AcquireShared (fragmentNum, buf, fragmentSize, isLast);
if (incompleteMessage->savedFragments.insert (savedFragment).second) if (incompleteMessage->savedFragments.insert (savedFragment).second)
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch (); incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
else else
LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved"); LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
@ -350,11 +350,11 @@ namespace transport
size += payload - fragment->buf; size += payload - fragment->buf;
uint8_t rem = size & 0x0F; uint8_t rem = size & 0x0F;
if (rem) // make sure 16 bytes boundary if (rem) // make sure 16 bytes boundary
{ {
auto padding = 16 - rem; auto padding = 16 - rem;
memset (fragment->buf + size, 0, padding); memset (fragment->buf + size, 0, padding);
size += padding; size += padding;
} }
fragment->len = size; fragment->len = size;
fragments.push_back (fragment); fragments.push_back (fragment);
@ -409,14 +409,14 @@ namespace transport
// one ack // one ack
*(uint32_t *)(payload) = htobe32 (msgID); // msgID *(uint32_t *)(payload) = htobe32 (msgID); // msgID
payload += 4; payload += 4;
size_t len = 0; size_t len = 0;
while (bits) while (bits)
{ {
*payload = (bits & 0x7F); // next 7 bits *payload = (bits & 0x7F); // next 7 bits
bits >>= 7; bits >>= 7;
if (bits) *payload &= 0x80; // 0x80 means non-last if (bits) *payload &= 0x80; // 0x80 means non-last
payload++; len++; payload++; len++;
} }
*payload = 0; // number of fragments *payload = 0; // number of fragments
len = (len <= 4) ? 48 : 64; // 48 = 37 + 7 + 4 len = (len <= 4) ? 48 : 64; // 48 = 37 + 7 + 4
// encrypt message with session key // encrypt message with session key
@ -450,7 +450,7 @@ namespace transport
if (f) if (f)
{ {
try try
{ {
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, f->buf, f->len, buf); m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, f->buf, f->len, buf);
m_Session.Send (buf, f->len); // resend m_Session.Send (buf, f->len); // resend
numResent++; numResent++;
@ -497,21 +497,21 @@ namespace transport
else else
++it; ++it;
} }
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES || ts > m_LastMessageReceivedTime + DECAY_INTERVAL) if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES || ts > m_LastMessageReceivedTime + DECAY_INTERVAL)
// decay // decay
m_ReceivedMessages.clear (); m_ReceivedMessages.clear ();
else else
{ {
// delete old received messages // delete old received messages
for (auto it = m_ReceivedMessages.begin (); it != m_ReceivedMessages.end ();) for (auto it = m_ReceivedMessages.begin (); it != m_ReceivedMessages.end ();)
{ {
if (ts > it->second + RECEIVED_MESSAGES_CLEANUP_TIMEOUT) if (ts > it->second + RECEIVED_MESSAGES_CLEANUP_TIMEOUT)
it = m_ReceivedMessages.erase (it); it = m_ReceivedMessages.erase (it);
else else
++it; ++it;
} }
} }
} }
} }
} }

View File

@ -79,7 +79,7 @@ namespace transport
uint64_t receivedFragmentsBits; uint64_t receivedFragmentsBits;
std::set<std::shared_ptr<Fragment>, FragmentCmp> savedFragments; std::set<std::shared_ptr<Fragment>, FragmentCmp> savedFragments;
IncompleteMessage (std::shared_ptr<I2NPMessage> m): msg (m), nextFragmentNum (0), IncompleteMessage (std::shared_ptr<I2NPMessage> m): msg (m), nextFragmentNum (0),
lastFragmentInsertTime (0), receivedFragmentsBits (0) {}; lastFragmentInsertTime (0), receivedFragmentsBits (0) {};
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize); void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
}; };
@ -102,7 +102,7 @@ namespace transport
void Start (); void Start ();
void Stop (); void Stop ();
void CleanUp (uint64_t ts); void CleanUp (uint64_t ts);
void ProcessMessage (uint8_t * buf, size_t len); void ProcessMessage (uint8_t * buf, size_t len);
void FlushReceivedMessage (); void FlushReceivedMessage ();
void Send (std::shared_ptr<i2p::I2NPMessage> msg); void Send (std::shared_ptr<i2p::I2NPMessage> msg);

View File

@ -230,7 +230,7 @@ namespace transport
auto pair = std::make_shared<i2p::crypto::DHKeys> (); auto pair = std::make_shared<i2p::crypto::DHKeys> ();
pair->GenerateKeys (); pair->GenerateKeys ();
m_DHKeysPair = pair; m_DHKeysPair = pair;
} }
CreateAESandMacKey (buf + headerSize); CreateAESandMacKey (buf + headerSize);
SendSessionCreated (buf + headerSize, sendRelayTag); SendSessionCreated (buf + headerSize, sendRelayTag);
} }
@ -259,7 +259,7 @@ namespace transport
s.Insert (y, 256); // y s.Insert (y, 256); // y
payload += 256; payload += 256;
boost::asio::ip::address ourIP; boost::asio::ip::address ourIP;
uint16_t ourPort = 0; uint16_t ourPort = 0;
auto addressAndPortLen = ExtractIPAddressAndPort (payload, len, ourIP, ourPort); auto addressAndPortLen = ExtractIPAddressAndPort (payload, len, ourIP, ourPort);
if (!addressAndPortLen) return; if (!addressAndPortLen) return;
uint8_t * ourAddressAndPort = payload + 1; uint8_t * ourAddressAndPort = payload + 1;
@ -297,15 +297,15 @@ namespace transport
{ {
LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort); LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort);
if (!i2p::util::net::IsInReservedRange (ourIP)) if (!i2p::util::net::IsInReservedRange (ourIP))
{ {
i2p::context.UpdateAddress (ourIP); i2p::context.UpdateAddress (ourIP);
SendSessionConfirmed (y, ourAddressAndPort, addressAndPortLen); SendSessionConfirmed (y, ourAddressAndPort, addressAndPortLen);
} }
else else
{ {
LogPrint (eLogError, "SSU: External address ", ourIP.to_string (), " is in reserved range"); LogPrint (eLogError, "SSU: External address ", ourIP.to_string (), " is in reserved range");
Failed (); Failed ();
} }
} }
else else
{ {
@ -317,7 +317,7 @@ namespace transport
void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len) void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len)
{ {
LogPrint (eLogDebug, "SSU: Session confirmed received"); LogPrint (eLogDebug, "SSU: Session confirmed received");
m_ConnectTimer.cancel (); m_ConnectTimer.cancel ();
auto headerSize = GetSSUHeaderSize (buf); auto headerSize = GetSSUHeaderSize (buf);
if (headerSize >= len) if (headerSize >= len)
{ {
@ -331,7 +331,7 @@ namespace transport
{ {
LogPrint (eLogError, "SSU: Session confirmed identity size ", identitySize, " exceeds packet length ", len); LogPrint (eLogError, "SSU: Session confirmed identity size ", identitySize, " exceeds packet length ", len);
return; return;
} }
payload += 2; // size of identity fragment payload += 2; // size of identity fragment
auto identity = std::make_shared<i2p::data::IdentityEx> (payload, identitySize); auto identity = std::make_shared<i2p::data::IdentityEx> (payload, identitySize);
auto existing = i2p::data::netdb.FindRouter (identity->GetIdentHash ()); // check if exists already auto existing = i2p::data::netdb.FindRouter (identity->GetIdentHash ()); // check if exists already
@ -357,7 +357,7 @@ namespace transport
{ {
LogPrint (eLogError, "SSU: Session confirmed message is too short ", len); LogPrint (eLogError, "SSU: Session confirmed message is too short ", len);
return; return;
} }
// verify signature // verify signature
if (m_SignedData && m_SignedData->Verify (m_RemoteIdentity, payload)) if (m_SignedData && m_SignedData->Verify (m_RemoteIdentity, payload))
{ {
@ -599,19 +599,19 @@ namespace transport
uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * payload = buf + sizeof (SSUHeader);
// Charlie // Charlie
if (isV4) if (isV4)
{ {
*payload = 4; *payload = 4;
payload++; // size payload++; // size
memcpy (payload, to.address ().to_v4 ().to_bytes ().data (), 4); // Charlie's IP V4 memcpy (payload, to.address ().to_v4 ().to_bytes ().data (), 4); // Charlie's IP V4
payload += 4; // address payload += 4; // address
} }
else else
{ {
*payload = 16; *payload = 16;
payload++; // size payload++; // size
memcpy (payload, to.address ().to_v6 ().to_bytes ().data (), 16); // Charlie's IP V6 memcpy (payload, to.address ().to_v6 ().to_bytes ().data (), 16); // Charlie's IP V6
payload += 16; // address payload += 16; // address
} }
htobe16buf (payload, to.port ()); // Charlie's port htobe16buf (payload, to.port ()); // Charlie's port
payload += 2; // port payload += 2; // port
// Alice // Alice
@ -705,15 +705,15 @@ namespace transport
else else
LogPrint (eLogError, "SSU: External address ", ourIP.to_string (), " is in reserved range"); LogPrint (eLogError, "SSU: External address ", ourIP.to_string (), " is in reserved range");
if (ourIP.is_v4 ()) if (ourIP.is_v4 ())
{ {
if (ourPort != m_Server.GetPort ()) if (ourPort != m_Server.GetPort ())
{ {
if (i2p::context.GetStatus () == eRouterStatusTesting) if (i2p::context.GetStatus () == eRouterStatusTesting)
i2p::context.SetError (eRouterErrorSymmetricNAT); i2p::context.SetError (eRouterErrorSymmetricNAT);
} }
else if (i2p::context.GetStatus () == eRouterStatusError && i2p::context.GetError () == eRouterErrorSymmetricNAT) else if (i2p::context.GetStatus () == eRouterStatusError && i2p::context.GetError () == eRouterErrorSymmetricNAT)
i2p::context.SetStatus (eRouterStatusTesting); i2p::context.SetStatus (eRouterStatusTesting);
} }
uint32_t nonce = bufbe32toh (buf); uint32_t nonce = bufbe32toh (buf);
buf += 4; // nonce buf += 4; // nonce
auto it = m_RelayRequests.find (nonce); auto it = m_RelayRequests.find (nonce);
@ -727,7 +727,7 @@ namespace transport
// now we do // now we do
LogPrint (eLogInfo, "SSU: RelayReponse connecting to endpoint ", remoteEndpoint); LogPrint (eLogInfo, "SSU: RelayReponse connecting to endpoint ", remoteEndpoint);
if ((remoteIP.is_v4 () && i2p::context.GetStatus () == eRouterStatusFirewalled) || if ((remoteIP.is_v4 () && i2p::context.GetStatus () == eRouterStatusFirewalled) ||
(remoteIP.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled)) (remoteIP.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled))
m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch
// we assume that HolePunch has been sent by this time and our SessionRequest will go through // we assume that HolePunch has been sent by this time and our SessionRequest will go through
m_Server.CreateDirectSession (it->second.first, remoteEndpoint, false); m_Server.CreateDirectSession (it->second.first, remoteEndpoint, false);
@ -803,7 +803,7 @@ namespace transport
htobe16buf (out + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8)); htobe16buf (out + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8));
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac); i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac);
} }
void SSUSession::Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey) void SSUSession::Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey)
{ {
if (len < sizeof (SSUHeader)) if (len < sizeof (SSUHeader))
@ -1015,7 +1015,7 @@ namespace transport
else else
++it; ++it;
} }
} }
void SSUSession::ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) void SSUSession::ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{ {
@ -1039,17 +1039,17 @@ namespace transport
LogPrint (eLogDebug, "SSU: Peer test from Bob. We are Alice"); LogPrint (eLogDebug, "SSU: Peer test from Bob. We are Alice");
if (IsV6 ()) if (IsV6 ())
{ {
if (i2p::context.GetStatusV6 () == eRouterStatusTesting) if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
{ {
i2p::context.SetStatusV6 (eRouterStatusFirewalled); i2p::context.SetStatusV6 (eRouterStatusFirewalled);
m_Server.RescheduleIntroducersUpdateTimerV6 (); m_Server.RescheduleIntroducersUpdateTimerV6 ();
} }
} }
else if (i2p::context.GetStatus () == eRouterStatusTesting) // still not OK else if (i2p::context.GetStatus () == eRouterStatusTesting) // still not OK
{ {
i2p::context.SetStatus (eRouterStatusFirewalled); i2p::context.SetStatus (eRouterStatusFirewalled);
m_Server.RescheduleIntroducersUpdateTimer (); m_Server.RescheduleIntroducersUpdateTimer ();
} }
} }
else else
{ {
@ -1058,7 +1058,7 @@ namespace transport
LogPrint (eLogWarning, "SSU: First peer test from Charlie through established session. We are Alice"); LogPrint (eLogWarning, "SSU: First peer test from Charlie through established session. We are Alice");
if (IsV6 ()) if (IsV6 ())
i2p::context.SetStatusV6 (eRouterStatusOK); i2p::context.SetStatusV6 (eRouterStatusOK);
else else
i2p::context.SetStatus (eRouterStatusOK); i2p::context.SetStatus (eRouterStatusOK);
m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2); m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2);
SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, true, false); // to Charlie SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, true, false); // to Charlie
@ -1074,8 +1074,8 @@ namespace transport
// peer test successive // peer test successive
LogPrint (eLogDebug, "SSU: Second peer test from Charlie. We are Alice"); LogPrint (eLogDebug, "SSU: Second peer test from Charlie. We are Alice");
if (IsV6 ()) if (IsV6 ())
i2p::context.SetStatusV6 (eRouterStatusOK); i2p::context.SetStatusV6 (eRouterStatusOK);
else else
i2p::context.SetStatus (eRouterStatusOK); i2p::context.SetStatus (eRouterStatusOK);
m_Server.RemovePeerTest (nonce); m_Server.RemovePeerTest (nonce);
} }
@ -1089,7 +1089,7 @@ namespace transport
{ {
const auto& ep = session->GetRemoteEndpoint (); // Alice's endpoint as known to Bob const auto& ep = session->GetRemoteEndpoint (); // Alice's endpoint as known to Bob
session->SendPeerTest (nonce, ep.address (), ep.port (), introKey, false, true); // send back to Alice session->SendPeerTest (nonce, ep.address (), ep.port (), introKey, false, true); // send back to Alice
} }
m_Server.RemovePeerTest (nonce); // nonce has been used m_Server.RemovePeerTest (nonce); // nonce has been used
break; break;
} }
@ -1111,10 +1111,10 @@ namespace transport
LogPrint (eLogDebug, "SSU: Peer test from Bob. We are Charlie"); LogPrint (eLogDebug, "SSU: Peer test from Bob. We are Charlie");
Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Bob Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Bob
if (!addr.is_unspecified () && !i2p::util::net::IsInReservedRange(addr)) if (!addr.is_unspecified () && !i2p::util::net::IsInReservedRange(addr))
{ {
m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie); m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie);
SendPeerTest (nonce, addr, port, introKey); // to Alice with her address received from Bob SendPeerTest (nonce, addr, port, introKey); // to Alice with her address received from Bob
} }
} }
else else
{ {
@ -1281,12 +1281,12 @@ namespace transport
if (!len) return 0; if (!len) return 0;
uint8_t size = *buf; uint8_t size = *buf;
size_t s = 1 + size + 2; // size + address + port size_t s = 1 + size + 2; // size + address + port
if (len < s) if (len < s)
{ {
LogPrint (eLogWarning, "SSU: Address is too short ", len); LogPrint (eLogWarning, "SSU: Address is too short ", len);
port = 0; port = 0;
return len; return len;
} }
buf++; // size buf++; // size
if (size == 4) if (size == 4)
{ {
@ -1299,12 +1299,12 @@ namespace transport
boost::asio::ip::address_v6::bytes_type bytes; boost::asio::ip::address_v6::bytes_type bytes;
memcpy (bytes.data (), buf, 16); memcpy (bytes.data (), buf, 16);
ip = boost::asio::ip::address_v6 (bytes); ip = boost::asio::ip::address_v6 (bytes);
} }
else else
LogPrint (eLogWarning, "SSU: Address size ", int(size), " is not supported"); LogPrint (eLogWarning, "SSU: Address size ", int(size), " is not supported");
buf += size; buf += size;
port = bufbe16toh (buf); port = bufbe16toh (buf);
return s; return s;
} }
} }
} }

View File

@ -90,7 +90,7 @@ namespace transport
void Failed (); void Failed ();
const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
SSUServer& GetServer () { return m_Server; }; SSUServer& GetServer () { return m_Server; };
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); }; bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs); void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
void SendPeerTest (); // Alice void SendPeerTest (); // Alice
@ -104,7 +104,7 @@ namespace transport
const i2p::data::RouterInfo::IntroKey& GetIntroKey () const { return m_IntroKey; }; const i2p::data::RouterInfo::IntroKey& GetIntroKey () const { return m_IntroKey; };
uint32_t GetCreationTime () const { return m_CreationTime; }; uint32_t GetCreationTime () const { return m_CreationTime; };
void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers
void FlushData (); void FlushData ();
void CleanUp (uint64_t ts); void CleanUp (uint64_t ts);
@ -149,7 +149,7 @@ namespace transport
void Reset (); void Reset ();
static size_t ExtractIPAddressAndPort (const uint8_t * buf, size_t len, boost::asio::ip::address& ip, uint16_t& port); // returns actual buf size static size_t ExtractIPAddressAndPort (const uint8_t * buf, size_t len, boost::asio::ip::address& ip, uint16_t& port); // returns actual buf size
private: private:
friend class SSUData; // TODO: change in later friend class SSUData; // TODO: change in later

View File

@ -115,7 +115,7 @@ namespace crypto
m_MDCtx = EVP_MD_CTX_create (); m_MDCtx = EVP_MD_CTX_create ();
EVP_DigestSignInit (m_MDCtx, NULL, NULL, NULL, pkey); EVP_DigestSignInit (m_MDCtx, NULL, NULL, NULL, pkey);
} }
EVP_PKEY_free (pkey); EVP_PKEY_free (pkey);
} }
EDDSA25519Signer::~EDDSA25519Signer () EDDSA25519Signer::~EDDSA25519Signer ()

View File

@ -340,7 +340,7 @@ namespace crypto
void Sign (const uint8_t * buf, int len, uint8_t * signature) const; void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
private: private:
EVP_MD_CTX * m_MDCtx; EVP_MD_CTX * m_MDCtx;
EDDSA25519SignerCompat * m_Fallback; EDDSA25519SignerCompat * m_Fallback;
}; };

View File

@ -27,12 +27,12 @@ namespace stream
void SendBufferQueue::Add (std::shared_ptr<SendBuffer> buf) void SendBufferQueue::Add (std::shared_ptr<SendBuffer> buf)
{ {
if (buf) if (buf)
{ {
m_Buffers.push_back (buf); m_Buffers.push_back (buf);
m_Size += buf->len; m_Size += buf->len;
} }
} }
size_t SendBufferQueue::Get (uint8_t * buf, size_t len) size_t SendBufferQueue::Get (uint8_t * buf, size_t len)
{ {
size_t offset = 0; size_t offset = 0;
@ -277,20 +277,20 @@ namespace stream
const uint8_t * optionData = packet->GetOptionData (); const uint8_t * optionData = packet->GetOptionData ();
size_t optionSize = packet->GetOptionSize (); size_t optionSize = packet->GetOptionSize ();
if (flags & PACKET_FLAG_DELAY_REQUESTED) if (flags & PACKET_FLAG_DELAY_REQUESTED)
{ {
if (!m_IsAckSendScheduled) if (!m_IsAckSendScheduled)
{ {
uint16_t delayRequested = bufbe16toh (optionData); uint16_t delayRequested = bufbe16toh (optionData);
if (delayRequested > 0 && delayRequested < m_RTT) if (delayRequested > 0 && delayRequested < m_RTT)
{ {
m_IsAckSendScheduled = true; m_IsAckSendScheduled = true;
m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(delayRequested)); m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(delayRequested));
m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer, m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
} }
optionData += 2; optionData += 2;
} }
if (flags & PACKET_FLAG_FROM_INCLUDED) if (flags & PACKET_FLAG_FROM_INCLUDED)
{ {
@ -391,10 +391,10 @@ namespace stream
p.len = payloadLen + 22; p.len = payloadLen + 22;
SendPackets (std::vector<Packet *> { &p }); SendPackets (std::vector<Packet *> { &p });
LogPrint (eLogDebug, "Streaming: Pong of ", p.len, " bytes sent"); LogPrint (eLogDebug, "Streaming: Pong of ", p.len, " bytes sent");
} }
m_LocalDestination.DeletePacket (packet); m_LocalDestination.DeletePacket (packet);
} }
void Stream::ProcessAck (Packet * packet) void Stream::ProcessAck (Packet * packet)
{ {
bool acknowledged = false; bool acknowledged = false;
@ -490,7 +490,7 @@ namespace stream
handler(boost::system::error_code ()); handler(boost::system::error_code ());
m_Service.post (std::bind (&Stream::SendBuffer, shared_from_this ())); m_Service.post (std::bind (&Stream::SendBuffer, shared_from_this ()));
} }
void Stream::SendBuffer () void Stream::SendBuffer ()
{ {
int numMsgs = m_WindowSize - m_SentPackets.size (); int numMsgs = m_WindowSize - m_SentPackets.size ();
@ -672,8 +672,8 @@ namespace stream
size_t size = 0; size_t size = 0;
htobe32buf (packet, m_RecvStreamID); htobe32buf (packet, m_RecvStreamID);
size += 4; // sendStreamID size += 4; // sendStreamID
memset (packet + size, 0, 14); memset (packet + size, 0, 14);
size += 14; // all zeroes size += 14; // all zeroes
uint16_t flags = PACKET_FLAG_ECHO | PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_FROM_INCLUDED; uint16_t flags = PACKET_FLAG_ECHO | PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_FROM_INCLUDED;
bool isOfflineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().IsOfflineSignature (); bool isOfflineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().IsOfflineSignature ();
if (isOfflineSignature) flags |= PACKET_FLAG_OFFLINE_SIGNATURE; if (isOfflineSignature) flags |= PACKET_FLAG_OFFLINE_SIGNATURE;
@ -695,12 +695,12 @@ namespace stream
memset (signature, 0, signatureLen); // zeroes for now memset (signature, 0, signatureLen); // zeroes for now
size += signatureLen; // signature size += signatureLen; // signature
htobe16buf (optionsSize, packet + size - 2 - optionsSize); // actual options size htobe16buf (optionsSize, packet + size - 2 - optionsSize); // actual options size
m_LocalDestination.GetOwner ()->Sign (packet, size, signature); m_LocalDestination.GetOwner ()->Sign (packet, size, signature);
p.len = size; p.len = size;
SendPackets (std::vector<Packet *> { &p }); SendPackets (std::vector<Packet *> { &p });
LogPrint (eLogDebug, "Streaming: Ping of ", p.len, " bytes sent"); LogPrint (eLogDebug, "Streaming: Ping of ", p.len, " bytes sent");
} }
void Stream::Close () void Stream::Close ()
{ {
LogPrint(eLogDebug, "Streaming: closing stream with sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID, ", status=", m_Status); LogPrint(eLogDebug, "Streaming: closing stream with sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID, ", status=", m_Status);
@ -840,7 +840,7 @@ namespace stream
auto leaseRouter = i2p::data::netdb.FindRouter (m_CurrentRemoteLease->tunnelGateway); auto leaseRouter = i2p::data::netdb.FindRouter (m_CurrentRemoteLease->tunnelGateway);
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (nullptr, m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (nullptr,
leaseRouter ? leaseRouter->GetCompatibleTransports (false) : (i2p::data::RouterInfo::CompatibleTransports)i2p::data::RouterInfo::eAllTransports); leaseRouter ? leaseRouter->GetCompatibleTransports (false) : (i2p::data::RouterInfo::CompatibleTransports)i2p::data::RouterInfo::eAllTransports);
} }
else if (!m_CurrentOutboundTunnel->IsEstablished ()) else if (!m_CurrentOutboundTunnel->IsEstablished ())
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel); m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel);
if (!m_CurrentOutboundTunnel) if (!m_CurrentOutboundTunnel)
@ -849,7 +849,7 @@ namespace stream
m_CurrentRemoteLease = nullptr; m_CurrentRemoteLease = nullptr;
return; return;
} }
std::vector<i2p::tunnel::TunnelMessageBlock> msgs; std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
for (const auto& it: packets) for (const auto& it: packets)
{ {
@ -903,14 +903,14 @@ namespace stream
void Stream::ScheduleResend () void Stream::ScheduleResend ()
{ {
if (m_Status != eStreamStatusTerminated) if (m_Status != eStreamStatusTerminated)
{ {
m_ResendTimer.cancel (); m_ResendTimer.cancel ();
// check for invalid value // check for invalid value
if (m_RTO <= 0) m_RTO = INITIAL_RTO; if (m_RTO <= 0) m_RTO = INITIAL_RTO;
m_ResendTimer.expires_from_now (boost::posix_time::milliseconds(m_RTO)); m_ResendTimer.expires_from_now (boost::posix_time::milliseconds(m_RTO));
m_ResendTimer.async_wait (std::bind (&Stream::HandleResendTimer, m_ResendTimer.async_wait (std::bind (&Stream::HandleResendTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
} }
void Stream::HandleResendTimer (const boost::system::error_code& ecode) void Stream::HandleResendTimer (const boost::system::error_code& ecode)
@ -1008,16 +1008,16 @@ namespace stream
{ {
LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), m_RemoteLeaseSet ? " expired" : " not found"); LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), m_RemoteLeaseSet ? " expired" : " not found");
if (m_RemoteLeaseSet && m_RemoteLeaseSet->IsPublishedEncrypted ()) if (m_RemoteLeaseSet && m_RemoteLeaseSet->IsPublishedEncrypted ())
{ {
m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet ( m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet (
std::make_shared<i2p::data::BlindedPublicKey>(m_RemoteIdentity)); std::make_shared<i2p::data::BlindedPublicKey>(m_RemoteIdentity));
return; // we keep m_RemoteLeaseSet for possible next request return; // we keep m_RemoteLeaseSet for possible next request
} }
else else
{ {
m_RemoteLeaseSet = nullptr; m_RemoteLeaseSet = nullptr;
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt
} }
} }
else else
{ {
@ -1113,7 +1113,7 @@ namespace stream
it.second->Terminate (false); // we delete here it.second->Terminate (false); // we delete here
m_Streams.clear (); m_Streams.clear ();
m_IncomingStreams.clear (); m_IncomingStreams.clear ();
m_LastStream = nullptr; m_LastStream = nullptr;
} }
} }
@ -1123,7 +1123,7 @@ namespace stream
if (sendStreamID) if (sendStreamID)
{ {
if (!m_LastStream || sendStreamID != m_LastStream->GetRecvStreamID ()) if (!m_LastStream || sendStreamID != m_LastStream->GetRecvStreamID ())
{ {
auto it = m_Streams.find (sendStreamID); auto it = m_Streams.find (sendStreamID);
if (it != m_Streams.end ()) if (it != m_Streams.end ())
m_LastStream = it->second; m_LastStream = it->second;
@ -1138,7 +1138,7 @@ namespace stream
LogPrint (eLogInfo, "Streaming: Ping received sSID=", sendStreamID); LogPrint (eLogInfo, "Streaming: Ping received sSID=", sendStreamID);
auto s = std::make_shared<Stream> (m_Owner->GetService (), *this); auto s = std::make_shared<Stream> (m_Owner->GetService (), *this);
s->HandlePing (packet); s->HandlePing (packet);
} }
else else
{ {
LogPrint (eLogInfo, "Streaming: Unknown stream sSID=", sendStreamID); LogPrint (eLogInfo, "Streaming: Unknown stream sSID=", sendStreamID);
@ -1153,7 +1153,7 @@ namespace stream
LogPrint (eLogInfo, "Streaming: Pong received rSID=", packet->GetReceiveStreamID ()); LogPrint (eLogInfo, "Streaming: Pong received rSID=", packet->GetReceiveStreamID ());
DeletePacket (packet); DeletePacket (packet);
return; return;
} }
if (packet->IsSYN () && !packet->GetSeqn ()) // new incoming stream if (packet->IsSYN () && !packet->GetSeqn ()) // new incoming stream
{ {
uint32_t receiveStreamID = packet->GetReceiveStreamID (); uint32_t receiveStreamID = packet->GetReceiveStreamID ();
@ -1252,8 +1252,8 @@ namespace stream
{ {
auto s = std::make_shared<Stream> (m_Owner->GetService (), *this, remote, 0); auto s = std::make_shared<Stream> (m_Owner->GetService (), *this, remote, 0);
s->SendPing (); s->SendPing ();
} }
std::shared_ptr<Stream> StreamingDestination::CreateNewIncomingStream (uint32_t receiveStreamID) std::shared_ptr<Stream> StreamingDestination::CreateNewIncomingStream (uint32_t receiveStreamID)
{ {
auto s = std::make_shared<Stream> (m_Owner->GetService (), *this); auto s = std::make_shared<Stream> (m_Owner->GetService (), *this);

View File

@ -112,10 +112,10 @@ namespace stream
memcpy (buf, b, len); memcpy (buf, b, len);
} }
SendBuffer (size_t l): // create empty buffer SendBuffer (size_t l): // create empty buffer
len(l), offset (0) len(l), offset (0)
{ {
buf = new uint8_t[len]; buf = new uint8_t[len];
} }
~SendBuffer () ~SendBuffer ()
{ {
delete[] buf; delete[] buf;
@ -180,7 +180,7 @@ namespace stream
size_t Send (const uint8_t * buf, size_t len); size_t Send (const uint8_t * buf, size_t len);
void AsyncSend (const uint8_t * buf, size_t len, SendHandler handler); void AsyncSend (const uint8_t * buf, size_t len, SendHandler handler);
void SendPing (); void SendPing ();
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0); void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); }; size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); };

View File

@ -48,7 +48,7 @@ namespace util
return std::chrono::duration_cast<std::chrono::minutes>( return std::chrono::duration_cast<std::chrono::minutes>(
std::chrono::system_clock::now().time_since_epoch()).count (); std::chrono::system_clock::now().time_since_epoch()).count ();
} }
static uint32_t GetLocalHoursSinceEpoch () static uint32_t GetLocalHoursSinceEpoch ()
{ {
return std::chrono::duration_cast<std::chrono::hours>( return std::chrono::duration_cast<std::chrono::hours>(
@ -70,23 +70,23 @@ namespace util
boost::asio::ip::udp::resolver::iterator end; boost::asio::ip::udp::resolver::iterator end;
boost::asio::ip::udp::endpoint ep; boost::asio::ip::udp::endpoint ep;
while (it != end) while (it != end)
{ {
ep = *it; ep = *it;
if (!ep.address ().is_unspecified ()) if (!ep.address ().is_unspecified ())
{ {
if (ep.address ().is_v4 ()) if (ep.address ().is_v4 ())
{ {
if (i2p::context.SupportsV4 ()) found = true; if (i2p::context.SupportsV4 ()) found = true;
} }
else if (ep.address ().is_v6 ()) else if (ep.address ().is_v6 ())
{ {
if (i2p::util::net::IsYggdrasilAddress (ep.address ())) if (i2p::util::net::IsYggdrasilAddress (ep.address ()))
{ {
if (i2p::context.SupportsMesh ()) found = true; if (i2p::context.SupportsMesh ()) found = true;
} }
else if (i2p::context.SupportsV6 ()) found = true; else if (i2p::context.SupportsV6 ()) found = true;
} }
} }
if (found) break; if (found) break;
it++; it++;
} }
@ -94,8 +94,8 @@ namespace util
{ {
LogPrint (eLogError, "Timestamp: can't find compatible address for ", address); LogPrint (eLogError, "Timestamp: can't find compatible address for ", address);
return; return;
} }
boost::asio::ip::udp::socket socket (service); boost::asio::ip::udp::socket socket (service);
socket.open (ep.protocol (), ec); socket.open (ep.protocol (), ec);
if (!ec) if (!ec)
@ -220,13 +220,13 @@ namespace util
uint64_t GetSecondsSinceEpoch () uint64_t GetSecondsSinceEpoch ()
{ {
return GetLocalSecondsSinceEpoch () + g_TimeOffset; return GetLocalSecondsSinceEpoch () + g_TimeOffset;
} }
uint32_t GetMinutesSinceEpoch () uint32_t GetMinutesSinceEpoch ()
{ {
return GetLocalMinutesSinceEpoch () + g_TimeOffset/60; return GetLocalMinutesSinceEpoch () + g_TimeOffset/60;
} }
uint32_t GetHoursSinceEpoch () uint32_t GetHoursSinceEpoch ()
{ {
return GetLocalHoursSinceEpoch () + g_TimeOffset/3600; return GetLocalHoursSinceEpoch () + g_TimeOffset/3600;

View File

@ -204,7 +204,7 @@ namespace transport
// create SSU server // create SSU server
int ssuPort = 0; int ssuPort = 0;
if (enableSSU) if (enableSSU)
{ {
auto& addresses = context.GetRouterInfo ().GetAddresses (); auto& addresses = context.GetRouterInfo ().GetAddresses ();
for (const auto& address: addresses) for (const auto& address: addresses)
{ {
@ -216,39 +216,39 @@ namespace transport
break; break;
} }
} }
} }
// bind to interfaces // bind to interfaces
bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool ipv4; i2p::config::GetOption("ipv4", ipv4);
if (ipv4) if (ipv4)
{ {
std::string address; i2p::config::GetOption("address4", address); std::string address; i2p::config::GetOption("address4", address);
if (!address.empty ()) if (!address.empty ())
{ {
boost::system::error_code ec; boost::system::error_code ec;
auto addr = boost::asio::ip::address::from_string (address, ec); auto addr = boost::asio::ip::address::from_string (address, ec);
if (!ec) if (!ec)
{ {
if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr); if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
if (m_SSUServer) m_SSUServer->SetLocalAddress (addr); if (m_SSUServer) m_SSUServer->SetLocalAddress (addr);
} }
} }
} }
bool ipv6; i2p::config::GetOption("ipv6", ipv6); bool ipv6; i2p::config::GetOption("ipv6", ipv6);
if (ipv6) if (ipv6)
{ {
std::string address; i2p::config::GetOption("address6", address); std::string address; i2p::config::GetOption("address6", address);
if (!address.empty ()) if (!address.empty ())
{ {
boost::system::error_code ec; boost::system::error_code ec;
auto addr = boost::asio::ip::address::from_string (address, ec); auto addr = boost::asio::ip::address::from_string (address, ec);
if (!ec) if (!ec)
{ {
if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr); if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr);
if (m_SSUServer) m_SSUServer->SetLocalAddress (addr); if (m_SSUServer) m_SSUServer->SetLocalAddress (addr);
} }
} }
} }
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
@ -256,12 +256,12 @@ namespace transport
{ {
std::string address; i2p::config::GetOption("meshnets.yggaddress", address); std::string address; i2p::config::GetOption("meshnets.yggaddress", address);
if (!address.empty ()) if (!address.empty ())
{ {
boost::system::error_code ec; boost::system::error_code ec;
auto addr = boost::asio::ip::address::from_string (address, ec); auto addr = boost::asio::ip::address::from_string (address, ec);
if (!ec && m_NTCP2Server && i2p::util::net::IsYggdrasilAddress (addr)) if (!ec && m_NTCP2Server && i2p::util::net::IsYggdrasilAddress (addr))
m_NTCP2Server->SetLocalAddress (addr); m_NTCP2Server->SetLocalAddress (addr);
} }
} }
// start servers // start servers
@ -269,11 +269,11 @@ namespace transport
if (m_SSUServer) if (m_SSUServer)
{ {
LogPrint (eLogInfo, "Transports: Start listening UDP port ", ssuPort); LogPrint (eLogInfo, "Transports: Start listening UDP port ", ssuPort);
try try
{ {
m_SSUServer->Start (); m_SSUServer->Start ();
} }
catch (std::exception& ex ) catch (std::exception& ex )
{ {
LogPrint(eLogError, "Transports: Failed to bind to UDP port", ssuPort); LogPrint(eLogError, "Transports: Failed to bind to UDP port", ssuPort);
m_SSUServer->Stop (); m_SSUServer->Stop ();
@ -281,8 +281,8 @@ namespace transport
m_SSUServer = nullptr; m_SSUServer = nullptr;
} }
if (m_SSUServer) DetectExternalIP (); if (m_SSUServer) DetectExternalIP ();
} }
m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
@ -448,23 +448,23 @@ namespace transport
if (!peer.numAttempts) // NTCP2 ipv6 if (!peer.numAttempts) // NTCP2 ipv6
{ {
if (context.GetRouterInfo ().IsNTCP2V6 () && peer.router->IsReachableBy (RouterInfo::eNTCP2V6)) if (context.GetRouterInfo ().IsNTCP2V6 () && peer.router->IsReachableBy (RouterInfo::eNTCP2V6))
{ {
address = peer.router->GetPublishedNTCP2V6Address (); address = peer.router->GetPublishedNTCP2V6Address ();
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
address = nullptr; address = nullptr;
} }
peer.numAttempts++; peer.numAttempts++;
} }
if (!address && peer.numAttempts == 1) // NTCP2 ipv4 if (!address && peer.numAttempts == 1) // NTCP2 ipv4
{ {
if (context.GetRouterInfo ().IsNTCP2 (true) && peer.router->IsReachableBy (RouterInfo::eNTCP2V4)) if (context.GetRouterInfo ().IsNTCP2 (true) && peer.router->IsReachableBy (RouterInfo::eNTCP2V4))
{ {
address = peer.router->GetPublishedNTCP2V4Address (); address = peer.router->GetPublishedNTCP2V4Address ();
if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host)) if (address && m_CheckReserved && i2p::util::net::IsInReservedRange(address->host))
address = nullptr; address = nullptr;
} }
peer.numAttempts++; peer.numAttempts++;
} }
if (address) if (address)
{ {
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address); auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
@ -478,10 +478,10 @@ namespace transport
else else
peer.numAttempts = 2; // switch to SSU peer.numAttempts = 2; // switch to SSU
} }
if (peer.numAttempts == 2 || peer.numAttempts == 3) // SSU if (peer.numAttempts == 2 || peer.numAttempts == 3) // SSU
{ {
if (m_SSUServer) if (m_SSUServer)
{ {
std::shared_ptr<const RouterInfo::Address> address; std::shared_ptr<const RouterInfo::Address> address;
if (peer.numAttempts == 2) // SSU ipv6 if (peer.numAttempts == 2) // SSU ipv6
{ {
@ -507,7 +507,7 @@ namespace transport
{ {
if (m_SSUServer->CreateSession (peer.router, address)) if (m_SSUServer->CreateSession (peer.router, address))
return true; return true;
} }
} }
else else
peer.numAttempts += 2; // switch to Mesh peer.numAttempts += 2; // switch to Mesh
@ -523,8 +523,8 @@ namespace transport
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address); auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router, address);
m_NTCP2Server->Connect (s); m_NTCP2Server->Connect (s);
return true; return true;
} }
} }
} }
LogPrint (eLogInfo, "Transports: No compatble NTCP2 or SSU addresses available"); LogPrint (eLogInfo, "Transports: No compatble NTCP2 or SSU addresses available");
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed
@ -591,7 +591,7 @@ namespace transport
bool statusChanged = false; bool statusChanged = false;
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{ {
auto router = i2p::data::netdb.GetRandomPeerTestRouter (true, excluded); // v4 auto router = i2p::data::netdb.GetRandomPeerTestRouter (true, excluded); // v4
if (router) if (router)
{ {
auto addr = router->GetSSUAddress (true); // ipv4 auto addr = router->GetSSUAddress (true); // ipv4
@ -602,8 +602,8 @@ namespace transport
statusChanged = true; statusChanged = true;
i2p::context.SetStatus (eRouterStatusTesting); // first time only i2p::context.SetStatus (eRouterStatusTesting); // first time only
} }
m_SSUServer->CreateSession (router, addr, true); // peer test v4 m_SSUServer->CreateSession (router, addr, true); // peer test v4
} }
excluded.insert (router->GetIdentHash ()); excluded.insert (router->GetIdentHash ());
} }
} }
@ -622,20 +622,20 @@ namespace transport
{ {
auto addr = router->GetSSUV6Address (); auto addr = router->GetSSUV6Address ();
if (addr && !i2p::util::net::IsInReservedRange(addr->host)) if (addr && !i2p::util::net::IsInReservedRange(addr->host))
{ {
if (!statusChanged) if (!statusChanged)
{ {
statusChanged = true; statusChanged = true;
i2p::context.SetStatusV6 (eRouterStatusTesting); // first time only i2p::context.SetStatusV6 (eRouterStatusTesting); // first time only
} }
m_SSUServer->CreateSession (router, addr, true); // peer test v6 m_SSUServer->CreateSession (router, addr, true); // peer test v6
} }
excluded.insert (router->GetIdentHash ()); excluded.insert (router->GetIdentHash ());
} }
} }
if (!statusChanged) if (!statusChanged)
LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6"); LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6");
} }
} }
std::shared_ptr<i2p::crypto::X25519Keys> Transports::GetNextX25519KeysPair () std::shared_ptr<i2p::crypto::X25519Keys> Transports::GetNextX25519KeysPair ()
@ -780,7 +780,7 @@ namespace transport
std::advance (it, rand () % m_Peers.size ()); std::advance (it, rand () % m_Peers.size ());
if (it == m_Peers.end () || it->second.router) return nullptr; // not connected if (it == m_Peers.end () || it->second.router) return nullptr; // not connected
ident = it->first; ident = it->first;
} }
return i2p::data::netdb.FindRouter (ident); return i2p::data::netdb.FindRouter (ident);
} }
void Transports::RestrictRoutesToFamilies(std::set<std::string> families) void Transports::RestrictRoutesToFamilies(std::set<std::string> families)

View File

@ -60,7 +60,7 @@ namespace transport
std::mutex m_AcquiredMutex; std::mutex m_AcquiredMutex;
}; };
typedef EphemeralKeysSupplier<i2p::crypto::X25519Keys> X25519KeysPairSupplier; typedef EphemeralKeysSupplier<i2p::crypto::X25519Keys> X25519KeysPairSupplier;
struct Peer struct Peer
{ {
int numAttempts; int numAttempts;

View File

@ -31,7 +31,7 @@ namespace tunnel
{ {
Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config): Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config):
TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()), TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()),
m_Config (config), m_IsShortBuildMessage (false), m_Pool (nullptr), m_Config (config), m_IsShortBuildMessage (false), m_Pool (nullptr),
m_State (eTunnelStatePending), m_FarEndTransports (i2p::data::RouterInfo::eAllTransports), m_State (eTunnelStatePending), m_FarEndTransports (i2p::data::RouterInfo::eAllTransports),
m_IsRecreated (false), m_Latency (0) m_IsRecreated (false), m_Latency (0)
{ {
@ -47,7 +47,7 @@ namespace tunnel
const int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : MAX_NUM_RECORDS; const int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : MAX_NUM_RECORDS;
auto msg = numRecords <= STANDARD_NUM_RECORDS ? NewI2NPShortMessage () : NewI2NPMessage (); auto msg = numRecords <= STANDARD_NUM_RECORDS ? NewI2NPShortMessage () : NewI2NPMessage ();
*msg->GetPayload () = numRecords; *msg->GetPayload () = numRecords;
const size_t recordSize = m_Config->IsShort () ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE; const size_t recordSize = m_Config->IsShort () ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE;
msg->len += numRecords*recordSize + 1; msg->len += numRecords*recordSize + 1;
// shuffle records // shuffle records
std::vector<int> recordIndicies; std::vector<int> recordIndicies;
@ -98,13 +98,13 @@ namespace tunnel
{ {
auto ident = m_Config->GetFirstHop () ? m_Config->GetFirstHop ()->ident : nullptr; auto ident = m_Config->GetFirstHop () ? m_Config->GetFirstHop ()->ident : nullptr;
if (ident && ident->GetIdentHash () != outboundTunnel->GetNextIdentHash ()) // don't encrypt if IBGW = OBEP if (ident && ident->GetIdentHash () != outboundTunnel->GetNextIdentHash ()) // don't encrypt if IBGW = OBEP
{ {
auto msg1 = i2p::garlic::WrapECIESX25519MessageForRouter (msg, ident->GetEncryptionPublicKey ()); auto msg1 = i2p::garlic::WrapECIESX25519MessageForRouter (msg, ident->GetEncryptionPublicKey ());
if (msg1) msg = msg1; if (msg1) msg = msg1;
} }
} }
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg); outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg);
} }
else else
{ {
if (m_Config->IsShort () && m_Config->GetLastHop () && if (m_Config->IsShort () && m_Config->GetLastHop () &&
@ -115,11 +115,11 @@ namespace tunnel
uint64_t tag = m_Config->GetLastHop ()->GetGarlicKey (key); uint64_t tag = m_Config->GetLastHop ()->GetGarlicKey (key);
if (m_Pool && m_Pool->GetLocalDestination ()) if (m_Pool && m_Pool->GetLocalDestination ())
m_Pool->GetLocalDestination ()->AddECIESx25519Key (key, tag); m_Pool->GetLocalDestination ()->AddECIESx25519Key (key, tag);
else else
i2p::context.AddECIESx25519Key (key, tag); i2p::context.AddECIESx25519Key (key, tag);
} }
i2p::transport::transports.SendMessage (GetNextIdentHash (), msg); i2p::transport::transports.SendMessage (GetNextIdentHash (), msg);
} }
} }
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len) bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)
@ -134,14 +134,14 @@ namespace tunnel
{ {
if (!hop->DecryptBuildResponseRecord (msg + 1)) if (!hop->DecryptBuildResponseRecord (msg + 1))
return false; return false;
} }
else else
{ {
LogPrint (eLogWarning, "Tunnel: Hop index ", hop->recordIndex, " is out of range"); LogPrint (eLogWarning, "Tunnel: Hop index ", hop->recordIndex, " is out of range");
return false; return false;
} }
// decrypt records before current hop // decrypt records before current hop
TunnelHopConfig * hop1 = hop->prev; TunnelHopConfig * hop1 = hop->prev;
while (hop1) while (hop1)
{ {
@ -176,7 +176,7 @@ namespace tunnel
// create tunnel decryptions from layer and iv keys in reverse order // create tunnel decryptions from layer and iv keys in reverse order
m_Hops.resize (numHops); m_Hops.resize (numHops);
hop = m_Config->GetLastHop (); hop = m_Config->GetLastHop ();
int i = 0; int i = 0;
while (hop) while (hop)
{ {
m_Hops[i].ident = hop->ident; m_Hops[i].ident = hop->ident;
@ -535,7 +535,7 @@ namespace tunnel
case eI2NPShortTunnelBuild: case eI2NPShortTunnelBuild:
case eI2NPShortTunnelBuildReply: case eI2NPShortTunnelBuildReply:
case eI2NPTunnelBuild: case eI2NPTunnelBuild:
case eI2NPTunnelBuildReply: case eI2NPTunnelBuildReply:
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
break; break;
default: default:
@ -566,14 +566,14 @@ namespace tunnel
{ {
ManageTunnelPools (ts); ManageTunnelPools (ts);
lastPoolsTs = ts; lastPoolsTs = ts;
} }
if (ts - lastMemoryPoolTs >= 120) // manage memory pool every 2 minutes if (ts - lastMemoryPoolTs >= 120) // manage memory pool every 2 minutes
{ {
m_I2NPTunnelEndpointMessagesMemoryPool.CleanUpMt (); m_I2NPTunnelEndpointMessagesMemoryPool.CleanUpMt ();
m_I2NPTunnelMessagesMemoryPool.CleanUpMt (); m_I2NPTunnelMessagesMemoryPool.CleanUpMt ();
lastMemoryPoolTs = ts; lastMemoryPoolTs = ts;
} }
} }
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
@ -848,7 +848,7 @@ namespace tunnel
} }
template<class TTunnel> template<class TTunnel>
std::shared_ptr<TTunnel> Tunnels::CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<TTunnel> Tunnels::CreateTunnel (std::shared_ptr<TunnelConfig> config,
std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel) std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel)
{ {
auto newTunnel = std::make_shared<TTunnel> (config); auto newTunnel = std::make_shared<TTunnel> (config);
@ -860,7 +860,7 @@ namespace tunnel
return newTunnel; return newTunnel;
} }
std::shared_ptr<InboundTunnel> Tunnels::CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<InboundTunnel> Tunnels::CreateInboundTunnel (std::shared_ptr<TunnelConfig> config,
std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel) std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel)
{ {
if (config) if (config)
@ -924,7 +924,7 @@ namespace tunnel
} }
std::shared_ptr<ZeroHopsInboundTunnel> Tunnels::CreateZeroHopsInboundTunnel (std::shared_ptr<TunnelPool> pool) std::shared_ptr<ZeroHopsInboundTunnel> Tunnels::CreateZeroHopsInboundTunnel (std::shared_ptr<TunnelPool> pool)
{ {
auto inboundTunnel = std::make_shared<ZeroHopsInboundTunnel> (); auto inboundTunnel = std::make_shared<ZeroHopsInboundTunnel> ();
inboundTunnel->SetTunnelPool (pool); inboundTunnel->SetTunnelPool (pool);
@ -947,21 +947,21 @@ namespace tunnel
std::shared_ptr<I2NPMessage> Tunnels::NewI2NPTunnelMessage (bool endpoint) std::shared_ptr<I2NPMessage> Tunnels::NewI2NPTunnelMessage (bool endpoint)
{ {
if (endpoint) if (endpoint)
{ {
// should fit two tunnel message + tunnel gateway header, enough for one garlic encrypted streaming packet // should fit two tunnel message + tunnel gateway header, enough for one garlic encrypted streaming packet
auto msg = m_I2NPTunnelEndpointMessagesMemoryPool.AcquireSharedMt (); auto msg = m_I2NPTunnelEndpointMessagesMemoryPool.AcquireSharedMt ();
msg->Align (6); msg->Align (6);
msg->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header msg->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header
return msg; return msg;
} }
else else
{ {
auto msg = m_I2NPTunnelMessagesMemoryPool.AcquireSharedMt (); auto msg = m_I2NPTunnelMessagesMemoryPool.AcquireSharedMt ();
msg->Align (12); msg->Align (12);
return msg; return msg;
} }
} }
int Tunnels::GetTransitTunnelsExpirationTimeout () int Tunnels::GetTransitTunnelsExpirationTimeout ()
{ {
int timeout = 0; int timeout = 0;

View File

@ -40,10 +40,10 @@ namespace tunnel
const int STANDARD_NUM_RECORDS = 4; // in VariableTunnelBuild message const int STANDARD_NUM_RECORDS = 4; // in VariableTunnelBuild message
const int MAX_NUM_RECORDS = 8; const int MAX_NUM_RECORDS = 8;
const int HIGH_LATENCY_PER_HOP = 250; // in milliseconds const int HIGH_LATENCY_PER_HOP = 250; // in milliseconds
const size_t I2NP_TUNNEL_MESSAGE_SIZE = TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34; // reserved for alignment and NTCP 16 + 6 + 12 const size_t I2NP_TUNNEL_MESSAGE_SIZE = TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34; // reserved for alignment and NTCP 16 + 6 + 12
const size_t I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE = 2*TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE + 28; // reserved for alignment and NTCP 16 + 6 + 6 const size_t I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE = 2*TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE + 28; // reserved for alignment and NTCP 16 + 6 + 6
enum TunnelState enum TunnelState
{ {
eTunnelStatePending, eTunnelStatePending,
@ -106,7 +106,7 @@ namespace tunnel
bool LatencyIsKnown() const { return m_Latency > 0; } bool LatencyIsKnown() const { return m_Latency > 0; }
bool IsSlow () const { return LatencyIsKnown() && (int)m_Latency > HIGH_LATENCY_PER_HOP*GetNumHops (); } bool IsSlow () const { return LatencyIsKnown() && (int)m_Latency > HIGH_LATENCY_PER_HOP*GetNumHops (); }
protected: protected:
void PrintHops (std::stringstream& s) const; void PrintHops (std::stringstream& s) const;
@ -119,7 +119,7 @@ namespace tunnel
std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null
TunnelState m_State; TunnelState m_State;
i2p::data::RouterInfo::CompatibleTransports m_FarEndTransports; i2p::data::RouterInfo::CompatibleTransports m_FarEndTransports;
bool m_IsRecreated; // if tunnel is replaced by new, or new tunnel requested to replace bool m_IsRecreated; // if tunnel is replaced by new, or new tunnel requested to replace
uint64_t m_Latency; // in milliseconds uint64_t m_Latency; // in milliseconds
}; };
@ -225,11 +225,11 @@ namespace tunnel
void StopTunnelPool (std::shared_ptr<TunnelPool> pool); void StopTunnelPool (std::shared_ptr<TunnelPool> pool);
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint); std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint);
private: private:
template<class TTunnel> template<class TTunnel>
std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config,
std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr); std::shared_ptr<TunnelPool> pool, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
template<class TTunnel> template<class TTunnel>
@ -266,7 +266,7 @@ namespace tunnel
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue; i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE> > m_I2NPTunnelEndpointMessagesMemoryPool; i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE> > m_I2NPTunnelEndpointMessagesMemoryPool;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool; i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool;
// some stats // some stats
int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations; int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations;

View File

@ -81,34 +81,34 @@ namespace tunnel
decryption.SetKey (replyKey); decryption.SetKey (replyKey);
decryption.SetIV (replyIV); decryption.SetIV (replyIV);
decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record); decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record);
} }
void ECIESTunnelHopConfig::EncryptECIES (const uint8_t * plainText, size_t len, uint8_t * encrypted) void ECIESTunnelHopConfig::EncryptECIES (const uint8_t * plainText, size_t len, uint8_t * encrypted)
{ {
if (!ident) return; if (!ident) return;
i2p::crypto::InitNoiseNState (*this, ident->GetEncryptionPublicKey ()); i2p::crypto::InitNoiseNState (*this, ident->GetEncryptionPublicKey ());
auto ephemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); auto ephemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
memcpy (encrypted, ephemeralKeys->GetPublicKey (), 32); memcpy (encrypted, ephemeralKeys->GetPublicKey (), 32);
MixHash (encrypted, 32); // h = SHA256(h || sepk) MixHash (encrypted, 32); // h = SHA256(h || sepk)
encrypted += 32; encrypted += 32;
uint8_t sharedSecret[32]; uint8_t sharedSecret[32];
ephemeralKeys->Agree (ident->GetEncryptionPublicKey (), sharedSecret); // x25519(sesk, hepk) ephemeralKeys->Agree (ident->GetEncryptionPublicKey (), sharedSecret); // x25519(sesk, hepk)
MixKey (sharedSecret); MixKey (sharedSecret);
uint8_t nonce[12]; uint8_t nonce[12];
memset (nonce, 0, 12); memset (nonce, 0, 12);
if (!i2p::crypto::AEADChaCha20Poly1305 (plainText, len, m_H, 32, m_CK + 32, nonce, encrypted, len + 16, true)) // encrypt if (!i2p::crypto::AEADChaCha20Poly1305 (plainText, len, m_H, 32, m_CK + 32, nonce, encrypted, len + 16, true)) // encrypt
{ {
LogPrint (eLogWarning, "Tunnel: Plaintext AEAD encryption failed"); LogPrint (eLogWarning, "Tunnel: Plaintext AEAD encryption failed");
return; return;
} }
MixHash (encrypted, len + 16); // h = SHA256(h || ciphertext) MixHash (encrypted, len + 16); // h = SHA256(h || ciphertext)
} }
bool ECIESTunnelHopConfig::DecryptECIES (const uint8_t * key, const uint8_t * nonce, const uint8_t * encrypted, size_t len, uint8_t * clearText) const bool ECIESTunnelHopConfig::DecryptECIES (const uint8_t * key, const uint8_t * nonce, const uint8_t * encrypted, size_t len, uint8_t * clearText) const
{ {
return i2p::crypto::AEADChaCha20Poly1305 (encrypted, len - 16, m_H, 32, key, nonce, clearText, len - 16, false); // decrypt return i2p::crypto::AEADChaCha20Poly1305 (encrypted, len - 16, m_H, 32, key, nonce, clearText, len - 16, false); // decrypt
} }
void LongECIESTunnelHopConfig::CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID) void LongECIESTunnelHopConfig::CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID)
{ {
// generate keys // generate keys
@ -119,7 +119,7 @@ namespace tunnel
// fill clear text // fill clear text
uint8_t flag = 0; uint8_t flag = 0;
if (isGateway) flag |= TUNNEL_BUILD_RECORD_GATEWAY_FLAG; if (isGateway) flag |= TUNNEL_BUILD_RECORD_GATEWAY_FLAG;
if (isEndpoint) flag |= TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; if (isEndpoint) flag |= TUNNEL_BUILD_RECORD_ENDPOINT_FLAG;
uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
htobe32buf (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID); htobe32buf (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID);
htobe32buf (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID); htobe32buf (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID);
@ -149,16 +149,16 @@ namespace tunnel
{ {
LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed"); LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed");
return false; return false;
} }
return true; return true;
} }
void ShortECIESTunnelHopConfig::CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID) void ShortECIESTunnelHopConfig::CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID)
{ {
// fill clear text // fill clear text
uint8_t flag = 0; uint8_t flag = 0;
if (isGateway) flag |= TUNNEL_BUILD_RECORD_GATEWAY_FLAG; if (isGateway) flag |= TUNNEL_BUILD_RECORD_GATEWAY_FLAG;
if (isEndpoint) flag |= TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; if (isEndpoint) flag |= TUNNEL_BUILD_RECORD_ENDPOINT_FLAG;
uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE ]; uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE ];
htobe32buf (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID); htobe32buf (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID);
htobe32buf (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID); htobe32buf (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID);
@ -174,21 +174,21 @@ namespace tunnel
uint8_t * record = records + recordIndex*SHORT_TUNNEL_BUILD_RECORD_SIZE; uint8_t * record = records + recordIndex*SHORT_TUNNEL_BUILD_RECORD_SIZE;
EncryptECIES (clearText, SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE, record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET); EncryptECIES (clearText, SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE, record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET);
// derive keys // derive keys
i2p::crypto::HKDF (m_CK, nullptr, 0, "SMTunnelReplyKey", m_CK); i2p::crypto::HKDF (m_CK, nullptr, 0, "SMTunnelReplyKey", m_CK);
memcpy (replyKey, m_CK + 32, 32); memcpy (replyKey, m_CK + 32, 32);
i2p::crypto::HKDF (m_CK, nullptr, 0, "SMTunnelLayerKey", m_CK); i2p::crypto::HKDF (m_CK, nullptr, 0, "SMTunnelLayerKey", m_CK);
memcpy (layerKey, m_CK + 32, 32); memcpy (layerKey, m_CK + 32, 32);
if (isEndpoint) if (isEndpoint)
{ {
i2p::crypto::HKDF (m_CK, nullptr, 0, "TunnelLayerIVKey", m_CK); i2p::crypto::HKDF (m_CK, nullptr, 0, "TunnelLayerIVKey", m_CK);
memcpy (ivKey, m_CK + 32, 32); memcpy (ivKey, m_CK + 32, 32);
i2p::crypto::HKDF (m_CK, nullptr, 0, "RGarlicKeyAndTag", m_CK); // OTBRM garlic key m_CK + 32, tag first 8 bytes of m_CK i2p::crypto::HKDF (m_CK, nullptr, 0, "RGarlicKeyAndTag", m_CK); // OTBRM garlic key m_CK + 32, tag first 8 bytes of m_CK
} }
else else
memcpy (ivKey, m_CK, 32); // last HKDF memcpy (ivKey, m_CK, 32); // last HKDF
memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16); memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16);
} }
bool ShortECIESTunnelHopConfig::DecryptBuildResponseRecord (uint8_t * records) const bool ShortECIESTunnelHopConfig::DecryptBuildResponseRecord (uint8_t * records) const
{ {
uint8_t * record = records + recordIndex*SHORT_TUNNEL_BUILD_RECORD_SIZE; uint8_t * record = records + recordIndex*SHORT_TUNNEL_BUILD_RECORD_SIZE;
@ -199,9 +199,9 @@ namespace tunnel
{ {
LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed"); LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed");
return false; return false;
} }
return true; return true;
} }
void ShortECIESTunnelHopConfig::DecryptRecord (uint8_t * records, int index) const void ShortECIESTunnelHopConfig::DecryptRecord (uint8_t * records, int index) const
{ {
@ -210,7 +210,7 @@ namespace tunnel
memset (nonce, 0, 12); memset (nonce, 0, 12);
nonce[4] = index; // nonce is index nonce[4] = index; // nonce is index
i2p::crypto::ChaCha20 (record, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, record); i2p::crypto::ChaCha20 (record, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, record);
} }
uint64_t ShortECIESTunnelHopConfig::GetGarlicKey (uint8_t * key) const uint64_t ShortECIESTunnelHopConfig::GetGarlicKey (uint8_t * key) const
{ {
@ -218,7 +218,7 @@ namespace tunnel
memcpy (&tag, m_CK, 8); memcpy (&tag, m_CK, 8);
memcpy (key, m_CK + 32, 32); memcpy (key, m_CK + 32, 32);
return tag; return tag;
} }
void TunnelConfig::CreatePeers (const std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers) void TunnelConfig::CreatePeers (const std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers)
{ {
@ -236,13 +236,13 @@ namespace tunnel
LogPrint (eLogError, "Tunnel: ElGamal router is not supported"); LogPrint (eLogError, "Tunnel: ElGamal router is not supported");
} }
if (hop) if (hop)
{ {
if (prev) if (prev)
prev->SetNext (hop); prev->SetNext (hop);
else else
m_FirstHop = hop; m_FirstHop = hop;
prev = hop; prev = hop;
} }
} }
m_LastHop = prev; m_LastHop = prev;
} }

View File

@ -116,8 +116,8 @@ namespace tunnel
i2p::data::RouterInfo::CompatibleTransports GetFarEndTransports () const i2p::data::RouterInfo::CompatibleTransports GetFarEndTransports () const
{ {
return m_FarEndTransports; return m_FarEndTransports;
} }
TunnelHopConfig * GetFirstHop () const TunnelHopConfig * GetFirstHop () const
{ {
return m_FirstHop; return m_FirstHop;

View File

@ -57,7 +57,7 @@ namespace tunnel
// first fragment // first fragment
if (m_CurrentMsgID) if (m_CurrentMsgID)
AddIncompleteCurrentMessage (); // we have got a new message while previous is not complete AddIncompleteCurrentMessage (); // we have got a new message while previous is not complete
m_CurrentMessage.deliveryType = (TunnelDeliveryType)((flag >> 5) & 0x03); m_CurrentMessage.deliveryType = (TunnelDeliveryType)((flag >> 5) & 0x03);
switch (m_CurrentMessage.deliveryType) switch (m_CurrentMessage.deliveryType)
{ {
@ -108,8 +108,8 @@ namespace tunnel
{ {
HandleFollowOnFragment (msgID, isLastFragment, fragmentNum, fragment, size); // another HandleFollowOnFragment (msgID, isLastFragment, fragmentNum, fragment, size); // another
m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr; m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
} }
} }
else else
{ {
// new message // new message
@ -131,27 +131,27 @@ namespace tunnel
} }
else else
m_CurrentMessage.data = msg; m_CurrentMessage.data = msg;
if (isLastFragment) if (isLastFragment)
{ {
// single message // single message
HandleNextMessage (m_CurrentMessage); HandleNextMessage (m_CurrentMessage);
m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr; m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
} }
else if (msgID) else if (msgID)
{ {
// first fragment of a new message // first fragment of a new message
m_CurrentMessage.nextFragmentNum = 1; m_CurrentMessage.nextFragmentNum = 1;
m_CurrentMessage.receiveTime = i2p::util::GetMillisecondsSinceEpoch (); m_CurrentMessage.receiveTime = i2p::util::GetMillisecondsSinceEpoch ();
HandleOutOfSequenceFragments (msgID, m_CurrentMessage); HandleOutOfSequenceFragments (msgID, m_CurrentMessage);
} }
else else
{ {
LogPrint (eLogError, "TunnelMessage: Message is fragmented, but msgID is not presented"); LogPrint (eLogError, "TunnelMessage: Message is fragmented, but msgID is not presented");
m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr; m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
} }
} }
fragment += size; fragment += size;
} }
} }
@ -159,7 +159,7 @@ namespace tunnel
LogPrint (eLogError, "TunnelMessage: Zero not found"); LogPrint (eLogError, "TunnelMessage: Zero not found");
} }
void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment,
uint8_t fragmentNum, const uint8_t * fragment, size_t size) uint8_t fragmentNum, const uint8_t * fragment, size_t size)
{ {
auto it = m_IncompleteMessages.find (msgID); auto it = m_IncompleteMessages.find (msgID);
@ -213,15 +213,15 @@ namespace tunnel
msg.data = newMsg; msg.data = newMsg;
} }
if (msg.data->Concat (fragment, size) < size) // concatenate fragment if (msg.data->Concat (fragment, size) < size) // concatenate fragment
{ {
LogPrint (eLogError, "TunnelMessage: I2NP buffer overflow ", msg.data->maxLen); LogPrint (eLogError, "TunnelMessage: I2NP buffer overflow ", msg.data->maxLen);
return false; return false;
} }
} }
else else
return false; return false;
return true; return true;
} }
void TunnelEndpoint::HandleCurrenMessageFollowOnFragment (const uint8_t * fragment, size_t size, bool isLastFragment) void TunnelEndpoint::HandleCurrenMessageFollowOnFragment (const uint8_t * fragment, size_t size, bool isLastFragment)
{ {
@ -244,7 +244,7 @@ namespace tunnel
LogPrint (eLogError, "TunnelMessage: Fragment ", m_CurrentMessage.nextFragmentNum, " of message ", m_CurrentMsgID, " exceeds max I2NP message size, message dropped"); LogPrint (eLogError, "TunnelMessage: Fragment ", m_CurrentMessage.nextFragmentNum, " of message ", m_CurrentMsgID, " exceeds max I2NP message size, message dropped");
m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr; m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
} }
} }
void TunnelEndpoint::AddIncompleteCurrentMessage () void TunnelEndpoint::AddIncompleteCurrentMessage ()
{ {
@ -255,13 +255,13 @@ namespace tunnel
LogPrint (eLogError, "TunnelMessage: Incomplete message ", m_CurrentMsgID, " already exists"); LogPrint (eLogError, "TunnelMessage: Incomplete message ", m_CurrentMsgID, " already exists");
m_CurrentMessage.data = nullptr; m_CurrentMessage.data = nullptr;
m_CurrentMsgID = 0; m_CurrentMsgID = 0;
} }
} }
void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum,
bool isLastFragment, const uint8_t * fragment, size_t size) bool isLastFragment, const uint8_t * fragment, size_t size)
{ {
std::unique_ptr<Fragment> f(new Fragment (isLastFragment, i2p::util::GetMillisecondsSinceEpoch (), size)); std::unique_ptr<Fragment> f(new Fragment (isLastFragment, i2p::util::GetMillisecondsSinceEpoch (), size));
memcpy (f->data.data (), fragment, size); memcpy (f->data.data (), fragment, size);
if (!m_OutOfSequenceFragments.emplace ((uint64_t)msgID << 32 | fragmentNum, std::move (f)).second) if (!m_OutOfSequenceFragments.emplace ((uint64_t)msgID << 32 | fragmentNum, std::move (f)).second)
LogPrint (eLogInfo, "TunnelMessage: Duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID); LogPrint (eLogInfo, "TunnelMessage: Duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID);
@ -276,10 +276,10 @@ namespace tunnel
HandleNextMessage (msg); HandleNextMessage (msg);
if (&msg == &m_CurrentMessage) if (&msg == &m_CurrentMessage)
{ {
m_CurrentMsgID = 0; m_CurrentMsgID = 0;
m_CurrentMessage.data = nullptr; m_CurrentMessage.data = nullptr;
} }
else else
m_IncompleteMessages.erase (msgID); m_IncompleteMessages.erase (msgID);
LogPrint (eLogDebug, "TunnelMessage: All fragments of message ", msgID, " found"); LogPrint (eLogDebug, "TunnelMessage: All fragments of message ", msgID, " found");
break; break;

View File

@ -49,14 +49,14 @@ namespace tunnel
void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, uint8_t fragmentNum, const uint8_t * fragment, size_t size); void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, uint8_t fragmentNum, const uint8_t * fragment, size_t size);
bool ConcatFollowOnFragment (TunnelMessageBlockEx& msg, const uint8_t * fragment, size_t size) const; // true if success bool ConcatFollowOnFragment (TunnelMessageBlockEx& msg, const uint8_t * fragment, size_t size) const; // true if success
void HandleCurrenMessageFollowOnFragment (const uint8_t * fragment, size_t size, bool isLastFragment); void HandleCurrenMessageFollowOnFragment (const uint8_t * fragment, size_t size, bool isLastFragment);
void HandleNextMessage (const TunnelMessageBlock& msg); void HandleNextMessage (const TunnelMessageBlock& msg);
void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, const uint8_t * fragment, size_t size); void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, const uint8_t * fragment, size_t size);
bool ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); // true if something added bool ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); // true if something added
void HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg); void HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg);
void AddIncompleteCurrentMessage (); void AddIncompleteCurrentMessage ();
private: private:
std::unordered_map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages; std::unordered_map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages;

View File

@ -187,7 +187,7 @@ namespace tunnel
RAND_bytes (m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE); RAND_bytes (m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE);
for (size_t i = 0; i < TUNNEL_DATA_MAX_PAYLOAD_SIZE; i++) for (size_t i = 0; i < TUNNEL_DATA_MAX_PAYLOAD_SIZE; i++)
if (!m_NonZeroRandomBuffer[i]) m_NonZeroRandomBuffer[i] = 1; if (!m_NonZeroRandomBuffer[i]) m_NonZeroRandomBuffer[i] = 1;
} }
auto randomOffset = rand () % (TUNNEL_DATA_MAX_PAYLOAD_SIZE - paddingSize + 1); auto randomOffset = rand () % (TUNNEL_DATA_MAX_PAYLOAD_SIZE - paddingSize + 1);
memcpy (buf + 24, m_NonZeroRandomBuffer + randomOffset, paddingSize); memcpy (buf + 24, m_NonZeroRandomBuffer + randomOffset, paddingSize);
} }

View File

@ -27,28 +27,28 @@ namespace tunnel
void Path::Add (std::shared_ptr<const i2p::data::RouterInfo> r) void Path::Add (std::shared_ptr<const i2p::data::RouterInfo> r)
{ {
if (r) if (r)
{ {
peers.push_back (r->GetRouterIdentity ()); peers.push_back (r->GetRouterIdentity ());
if (r->GetVersion () < i2p::data::NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION || if (r->GetVersion () < i2p::data::NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION ||
r->GetRouterIdentity ()->GetCryptoKeyType () != i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) r->GetRouterIdentity ()->GetCryptoKeyType () != i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
isShort = false; isShort = false;
} }
} }
void Path::Reverse () void Path::Reverse ()
{ {
std::reverse (peers.begin (), peers.end ()); std::reverse (peers.begin (), peers.end ());
} }
TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels): TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops), m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels),
m_IsActive (true), m_CustomPeerSelector(nullptr) m_IsActive (true), m_CustomPeerSelector(nullptr)
{ {
if (m_NumInboundTunnels > TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY) if (m_NumInboundTunnels > TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY)
m_NumInboundTunnels = TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY; m_NumInboundTunnels = TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY;
if (m_NumOutboundTunnels > TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY) if (m_NumOutboundTunnels > TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY)
m_NumOutboundTunnels = TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY; m_NumOutboundTunnels = TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY;
m_NextManageTime = i2p::util::GetSecondsSinceEpoch () + rand () % TUNNEL_POOL_MANAGE_INTERVAL; m_NextManageTime = i2p::util::GetSecondsSinceEpoch () + rand () % TUNNEL_POOL_MANAGE_INTERVAL;
} }
@ -114,7 +114,7 @@ namespace tunnel
{ {
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
if (createdTunnel->IsRecreated ()) if (createdTunnel->IsRecreated ())
{ {
// find and mark old tunnel as expired // find and mark old tunnel as expired
createdTunnel->SetRecreated (false); createdTunnel->SetRecreated (false);
for (auto& it: m_InboundTunnels) for (auto& it: m_InboundTunnels)
@ -122,8 +122,8 @@ namespace tunnel
{ {
it->SetState (eTunnelStateExpiring); it->SetState (eTunnelStateExpiring);
break; break;
} }
} }
m_InboundTunnels.insert (createdTunnel); m_InboundTunnels.insert (createdTunnel);
} }
if (m_LocalDestination) if (m_LocalDestination)
@ -179,10 +179,10 @@ namespace tunnel
if (it->IsSlow () && !slowTunnel) if (it->IsSlow () && !slowTunnel)
slowTunnel = it; slowTunnel = it;
else else
{ {
v.push_back (it); v.push_back (it);
i++; i++;
} }
} }
} }
if (slowTunnel && (int)v.size () < (num/2+1)) if (slowTunnel && (int)v.size () < (num/2+1))
@ -205,7 +205,7 @@ namespace tunnel
} }
template<class TTunnels> template<class TTunnels>
typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels,
typename TTunnels::value_type excluded, i2p::data::RouterInfo::CompatibleTransports compatible) const typename TTunnels::value_type excluded, i2p::data::RouterInfo::CompatibleTransports compatible) const
{ {
if (tunnels.empty ()) return nullptr; if (tunnels.empty ()) return nullptr;
@ -216,8 +216,8 @@ namespace tunnel
{ {
if (it->IsEstablished () && it != excluded && (compatible & it->GetFarEndTransports ())) if (it->IsEstablished () && it != excluded && (compatible & it->GetFarEndTransports ()))
{ {
if (it->IsSlow () || (HasLatencyRequirement() && it->LatencyIsKnown() && if (it->IsSlow () || (HasLatencyRequirement() && it->LatencyIsKnown() &&
!it->LatencyFitsRange(m_MinLatency, m_MaxLatency))) !it->LatencyFitsRange(m_MinLatency, m_MaxLatency)))
{ {
i++; skipped = true; i++; skipped = true;
continue; continue;
@ -227,7 +227,7 @@ namespace tunnel
} }
if (i > ind && tunnel) break; if (i > ind && tunnel) break;
} }
if (!tunnel && skipped) if (!tunnel && skipped)
{ {
ind = rand () % (tunnels.size ()/2 + 1), i = 0; ind = rand () % (tunnels.size ()/2 + 1), i = 0;
for (const auto& it: tunnels) for (const auto& it: tunnels)
@ -284,12 +284,12 @@ namespace tunnel
if (!num && !m_OutboundTunnels.empty () && m_NumOutboundHops > 0) if (!num && !m_OutboundTunnels.empty () && m_NumOutboundHops > 0)
{ {
for (auto it: m_OutboundTunnels) for (auto it: m_OutboundTunnels)
{ {
CreatePairedInboundTunnel (it); CreatePairedInboundTunnel (it);
num++; num++;
if (num >= m_NumInboundTunnels) break; if (num >= m_NumInboundTunnels) break;
} }
} }
for (int i = num; i < m_NumInboundTunnels; i++) for (int i = num; i < m_NumInboundTunnels; i++)
CreateInboundTunnel (); CreateInboundTunnel ();
@ -371,13 +371,13 @@ namespace tunnel
void TunnelPool::ManageTunnels (uint64_t ts) void TunnelPool::ManageTunnels (uint64_t ts)
{ {
if (ts > m_NextManageTime) if (ts > m_NextManageTime)
{ {
CreateTunnels (); CreateTunnels ();
TestTunnels (); TestTunnels ();
m_NextManageTime = ts + TUNNEL_POOL_MANAGE_INTERVAL + (rand () % TUNNEL_POOL_MANAGE_INTERVAL)/2; m_NextManageTime = ts + TUNNEL_POOL_MANAGE_INTERVAL + (rand () % TUNNEL_POOL_MANAGE_INTERVAL)/2;
} }
} }
void TunnelPool::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg) void TunnelPool::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{ {
if (m_LocalDestination) if (m_LocalDestination)
@ -412,19 +412,19 @@ namespace tunnel
uint64_t latency = dlt / 2; uint64_t latency = dlt / 2;
// restore from test failed state if any // restore from test failed state if any
if (test.first) if (test.first)
{ {
if (test.first->GetState () == eTunnelStateTestFailed) if (test.first->GetState () == eTunnelStateTestFailed)
test.first->SetState (eTunnelStateEstablished); test.first->SetState (eTunnelStateEstablished);
// update latency // update latency
test.first->AddLatencySample(latency); test.first->AddLatencySample(latency);
} }
if (test.second) if (test.second)
{ {
if (test.second->GetState () == eTunnelStateTestFailed) if (test.second->GetState () == eTunnelStateTestFailed)
test.second->SetState (eTunnelStateEstablished); test.second->SetState (eTunnelStateEstablished);
// update latency // update latency
test.second->AddLatencySample(latency); test.second->AddLatencySample(latency);
} }
} }
else else
{ {
@ -438,8 +438,8 @@ namespace tunnel
bool TunnelPool::IsExploratory () const bool TunnelPool::IsExploratory () const
{ {
return i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this (); return i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this ();
} }
std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, bool reverse) const std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, bool reverse) const
{ {
auto hop = IsExploratory () ? i2p::data::netdb.GetRandomRouter (prevHop, reverse): auto hop = IsExploratory () ? i2p::data::netdb.GetRandomRouter (prevHop, reverse):
@ -467,7 +467,7 @@ namespace tunnel
(inbound && i2p::transport::transports.GetNumPeers () > 25)) (inbound && i2p::transport::transports.GetNumPeers () > 25))
{ {
auto r = i2p::transport::transports.GetRandomPeer (); auto r = i2p::transport::transports.GetRandomPeer ();
if (r && r->IsECIES () && !r->GetProfile ()->IsBad () && if (r && r->IsECIES () && !r->GetProfile ()->IsBad () &&
(numHops > 1 || (r->IsV4 () && (!inbound || r->IsReachable ())))) // first inbound must be reachable (numHops > 1 || (r->IsV4 () && (!inbound || r->IsReachable ())))) // first inbound must be reachable
{ {
prevHop = r; prevHop = r;
@ -480,11 +480,11 @@ namespace tunnel
{ {
auto hop = nextHop (prevHop, inbound); auto hop = nextHop (prevHop, inbound);
if (!hop && !i) // if no suitable peer found for first hop, try already connected if (!hop && !i) // if no suitable peer found for first hop, try already connected
{ {
LogPrint (eLogInfo, "Tunnels: Can't select first hop for a tunnel. Trying already connected"); LogPrint (eLogInfo, "Tunnels: Can't select first hop for a tunnel. Trying already connected");
hop = i2p::transport::transports.GetRandomPeer (); hop = i2p::transport::transports.GetRandomPeer ();
if (hop && !hop->IsECIES ()) hop = nullptr; if (hop && !hop->IsECIES ()) hop = nullptr;
} }
if (!hop) if (!hop)
{ {
LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ()); LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ());
@ -495,7 +495,7 @@ namespace tunnel
{ {
auto hop1 = nextHop (prevHop, true); auto hop1 = nextHop (prevHop, true);
if (hop1) hop = hop1; if (hop1) hop = hop1;
} }
prevHop = hop; prevHop = hop;
path.Add (hop); path.Add (hop);
} }
@ -523,25 +523,25 @@ namespace tunnel
{ {
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
if (numHops > (int)m_ExplicitPeers->size ()) numHops = m_ExplicitPeers->size (); if (numHops > (int)m_ExplicitPeers->size ()) numHops = m_ExplicitPeers->size ();
if (!numHops) return false; if (!numHops) return false;
for (int i = 0; i < numHops; i++) for (int i = 0; i < numHops; i++)
{ {
auto& ident = (*m_ExplicitPeers)[i]; auto& ident = (*m_ExplicitPeers)[i];
auto r = i2p::data::netdb.FindRouter (ident); auto r = i2p::data::netdb.FindRouter (ident);
if (r) if (r)
{ {
if (r->IsECIES ()) if (r->IsECIES ())
{ {
path.Add (r); path.Add (r);
if (i == numHops - 1) if (i == numHops - 1)
path.farEndTransports = r->GetCompatibleTransports (isInbound); path.farEndTransports = r->GetCompatibleTransports (isInbound);
} }
else else
{ {
LogPrint (eLogError, "Tunnels: ElGamal router ", ident.ToBase64 (), " is not supported"); LogPrint (eLogError, "Tunnels: ElGamal router ", ident.ToBase64 (), " is not supported");
return false; return false;
} }
} }
else else
{ {
LogPrint (eLogInfo, "Tunnels: Can't find router for ", ident.ToBase64 ()); LogPrint (eLogInfo, "Tunnels: Can't find router for ", ident.ToBase64 ());
@ -612,14 +612,14 @@ namespace tunnel
{ {
LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no inbound tunnels found"); LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no inbound tunnels found");
return; return;
} }
if (m_LocalDestination && !m_LocalDestination->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) if (m_LocalDestination && !m_LocalDestination->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
path.isShort = false; // because can't handle ECIES encrypted reply path.isShort = false; // because can't handle ECIES encrypted reply
std::shared_ptr<TunnelConfig> config; std::shared_ptr<TunnelConfig> config;
if (m_NumOutboundHops > 0) if (m_NumOutboundHops > 0)
config = std::make_shared<TunnelConfig>(path.peers, inboundTunnel->GetNextTunnelID (), config = std::make_shared<TunnelConfig>(path.peers, inboundTunnel->GetNextTunnelID (),
inboundTunnel->GetNextIdentHash (), path.isShort, path.farEndTransports); inboundTunnel->GetNextIdentHash (), path.isShort, path.farEndTransports);
std::shared_ptr<OutboundTunnel> tunnel; std::shared_ptr<OutboundTunnel> tunnel;
@ -628,8 +628,8 @@ namespace tunnel
// TODO: implement it better // TODO: implement it better
tunnel = tunnels.CreateOutboundTunnel (config, inboundTunnel->GetTunnelPool ()); tunnel = tunnels.CreateOutboundTunnel (config, inboundTunnel->GetTunnelPool ());
tunnel->SetTunnelPool (shared_from_this ()); tunnel->SetTunnelPool (shared_from_this ());
} }
else else
tunnel = tunnels.CreateOutboundTunnel (config, shared_from_this ()); tunnel = tunnels.CreateOutboundTunnel (config, shared_from_this ());
if (tunnel && tunnel->IsEstablished ()) // zero hops if (tunnel && tunnel->IsEstablished ()) // zero hops
TunnelCreated (tunnel); TunnelCreated (tunnel);
@ -654,7 +654,7 @@ namespace tunnel
std::shared_ptr<TunnelConfig> config; std::shared_ptr<TunnelConfig> config;
if (m_NumOutboundHops > 0 && tunnel->GetPeers().size()) if (m_NumOutboundHops > 0 && tunnel->GetPeers().size())
{ {
config = std::make_shared<TunnelConfig>(tunnel->GetPeers (), inboundTunnel->GetNextTunnelID (), config = std::make_shared<TunnelConfig>(tunnel->GetPeers (), inboundTunnel->GetNextTunnelID (),
inboundTunnel->GetNextIdentHash (), inboundTunnel->IsShortBuildMessage (), tunnel->GetFarEndTransports ()); inboundTunnel->GetNextIdentHash (), inboundTunnel->IsShortBuildMessage (), tunnel->GetFarEndTransports ());
} }
if (!m_NumOutboundHops || config) if (!m_NumOutboundHops || config)
@ -673,7 +673,7 @@ namespace tunnel
LogPrint (eLogDebug, "Tunnels: Creating paired inbound tunnel..."); LogPrint (eLogDebug, "Tunnels: Creating paired inbound tunnel...");
auto tunnel = tunnels.CreateInboundTunnel ( auto tunnel = tunnels.CreateInboundTunnel (
m_NumOutboundHops > 0 ? std::make_shared<TunnelConfig>(outboundTunnel->GetInvertedPeers (), m_NumOutboundHops > 0 ? std::make_shared<TunnelConfig>(outboundTunnel->GetInvertedPeers (),
outboundTunnel->IsShortBuildMessage ()) : nullptr, outboundTunnel->IsShortBuildMessage ()) : nullptr,
shared_from_this (), outboundTunnel); shared_from_this (), outboundTunnel);
if (tunnel->IsEstablished ()) // zero hops if (tunnel->IsEstablished ()) // zero hops
TunnelCreated (tunnel); TunnelCreated (tunnel);

View File

@ -30,7 +30,7 @@ namespace tunnel
const int TUNNEL_POOL_MANAGE_INTERVAL = 10; // in seconds const int TUNNEL_POOL_MANAGE_INTERVAL = 10; // in seconds
const int TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY = 16; const int TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY = 16;
const int TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY = 16; const int TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY = 16;
class Tunnel; class Tunnel;
class InboundTunnel; class InboundTunnel;
class OutboundTunnel; class OutboundTunnel;
@ -41,7 +41,7 @@ namespace tunnel
std::vector<Peer> peers; std::vector<Peer> peers;
bool isShort = true; bool isShort = true;
i2p::data::RouterInfo::CompatibleTransports farEndTransports = i2p::data::RouterInfo::eAllTransports; i2p::data::RouterInfo::CompatibleTransports farEndTransports = i2p::data::RouterInfo::eAllTransports;
void Add (std::shared_ptr<const i2p::data::RouterInfo> r); void Add (std::shared_ptr<const i2p::data::RouterInfo> r);
void Reverse (); void Reverse ();
}; };
@ -56,7 +56,7 @@ namespace tunnel
typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>, bool)> SelectHopFunc; typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>, bool)> SelectHopFunc;
bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop); bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop);
class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination
{ {
public: public:
@ -122,7 +122,7 @@ namespace tunnel
void CreateOutboundTunnel (); void CreateOutboundTunnel ();
void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel); void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel);
template<class TTunnels> template<class TTunnels>
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels,
typename TTunnels::value_type excluded, i2p::data::RouterInfo::CompatibleTransports compatible) const; typename TTunnels::value_type excluded, i2p::data::RouterInfo::CompatibleTransports compatible) const;
bool SelectPeers (Path& path, bool isInbound); bool SelectPeers (Path& path, bool isInbound);
bool SelectExplicitPeers (Path& path, bool isInbound); bool SelectExplicitPeers (Path& path, bool isInbound);

View File

@ -425,14 +425,14 @@ namespace net
static bool IsYggdrasilAddress (const uint8_t addr[16]) static bool IsYggdrasilAddress (const uint8_t addr[16])
{ {
return addr[0] == 0x02 || addr[0] == 0x03; return addr[0] == 0x02 || addr[0] == 0x03;
} }
bool IsYggdrasilAddress (const boost::asio::ip::address& addr) bool IsYggdrasilAddress (const boost::asio::ip::address& addr)
{ {
if (!addr.is_v6 ()) return false; if (!addr.is_v6 ()) return false;
return IsYggdrasilAddress (addr.to_v6 ().to_bytes ().data ()); return IsYggdrasilAddress (addr.to_v6 ().to_bytes ().data ());
} }
boost::asio::ip::address_v6 GetYggdrasilAddress () boost::asio::ip::address_v6 GetYggdrasilAddress ()
{ {
#if defined(_WIN32) #if defined(_WIN32)
@ -517,11 +517,11 @@ namespace net
GetMTUWindows(addr, 0); GetMTUWindows(addr, 0);
#else #else
GetMTUUnix(addr, 0); GetMTUUnix(addr, 0);
#endif #endif
return mtu > 0; return mtu > 0;
} }
bool IsInReservedRange (const boost::asio::ip::address& host) bool IsInReservedRange (const boost::asio::ip::address& host)
{ {
// https://en.wikipedia.org/wiki/Reserved_IP_addresses // https://en.wikipedia.org/wiki/Reserved_IP_addresses
if (host.is_unspecified ()) return false; if (host.is_unspecified ()) return false;

View File

@ -58,8 +58,8 @@ namespace util
{ {
CleanUp (m_Head); CleanUp (m_Head);
m_Head = nullptr; m_Head = nullptr;
} }
template<typename... TArgs> template<typename... TArgs>
T * Acquire (TArgs&&... args) T * Acquire (TArgs&&... args)
{ {
@ -104,8 +104,8 @@ namespace util
head = static_cast<T*>(*(void * *)head); // next head = static_cast<T*>(*(void * *)head); // next
::operator delete ((void *)tmp); ::operator delete ((void *)tmp);
} }
} }
protected: protected:
T * m_Head; T * m_Head;
@ -152,11 +152,11 @@ namespace util
{ {
std::lock_guard<std::mutex> l(m_Mutex); std::lock_guard<std::mutex> l(m_Mutex);
head = this->m_Head; head = this->m_Head;
this->m_Head = nullptr; this->m_Head = nullptr;
} }
if (head) this->CleanUp (head); if (head) this->CleanUp (head);
} }
private: private:
std::mutex m_Mutex; std::mutex m_Mutex;

View File

@ -35,7 +35,7 @@ namespace client
class AddressBookFilesystemStorage: public AddressBookStorage class AddressBookFilesystemStorage: public AddressBookStorage
{ {
public: public:
AddressBookFilesystemStorage (): storage("addressbook", "b", "", "b32") AddressBookFilesystemStorage (): storage("addressbook", "b", "", "b32")
{ {
i2p::config::GetOption("persist.addressbook", m_IsPersist); i2p::config::GetOption("persist.addressbook", m_IsPersist);
@ -62,7 +62,7 @@ namespace client
private: private:
i2p::fs::HashedStorage storage; i2p::fs::HashedStorage storage;
std::string etagsPath, indexPath, localPath; std::string etagsPath, indexPath, localPath;
bool m_IsPersist; bool m_IsPersist;
std::string m_HostsFile; // file to dump hosts.txt, empty if not used std::string m_HostsFile; // file to dump hosts.txt, empty if not used
}; };
@ -185,7 +185,7 @@ namespace client
int AddressBookFilesystemStorage::Save (const std::map<std::string, std::shared_ptr<Address> >& addresses) int AddressBookFilesystemStorage::Save (const std::map<std::string, std::shared_ptr<Address> >& addresses)
{ {
if (addresses.empty()) if (addresses.empty())
{ {
LogPrint(eLogWarning, "Addressbook: Not saving empty addressbook"); LogPrint(eLogWarning, "Addressbook: Not saving empty addressbook");
return 0; return 0;
@ -200,7 +200,7 @@ namespace client
for (const auto& it: addresses) for (const auto& it: addresses)
{ {
if (it.second->IsValid ()) if (it.second->IsValid ())
{ {
f << it.first << ","; f << it.first << ",";
if (it.second->IsIdentHash ()) if (it.second->IsIdentHash ())
f << it.second->identHash.ToBase32 (); f << it.second->identHash.ToBase32 ();
@ -208,15 +208,15 @@ namespace client
f << it.second->blindedPublicKey->ToB33 (); f << it.second->blindedPublicKey->ToB33 ();
f << std::endl; f << std::endl;
num++; num++;
} }
else else
LogPrint (eLogWarning, "Addressbook: Invalid address ", it.first); LogPrint (eLogWarning, "Addressbook: Invalid address ", it.first);
} }
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved"); LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
} }
else else
LogPrint (eLogWarning, "Addressbook: Can't open ", indexPath); LogPrint (eLogWarning, "Addressbook: Can't open ", indexPath);
} }
if (!m_HostsFile.empty ()) if (!m_HostsFile.empty ())
{ {
// dump full hosts.txt // dump full hosts.txt
@ -226,18 +226,18 @@ namespace client
for (const auto& it: addresses) for (const auto& it: addresses)
{ {
std::shared_ptr<const i2p::data::IdentityEx> addr; std::shared_ptr<const i2p::data::IdentityEx> addr;
if (it.second->IsIdentHash ()) if (it.second->IsIdentHash ())
{ {
addr = GetAddress (it.second->identHash); addr = GetAddress (it.second->identHash);
if (addr) if (addr)
f << it.first << "=" << addr->ToBase64 () << std::endl; f << it.first << "=" << addr->ToBase64 () << std::endl;
} }
} }
} }
else else
LogPrint (eLogWarning, "Addressbook: Can't open ", m_HostsFile); LogPrint (eLogWarning, "Addressbook: Can't open ", m_HostsFile);
} }
return num; return num;
} }
@ -495,7 +495,7 @@ namespace client
if (it != m_Addresses.end ()) // already exists ? if (it != m_Addresses.end ()) // already exists ?
{ {
if (it->second->IsIdentHash () && it->second->identHash != ident->GetIdentHash () && // address changed? if (it->second->IsIdentHash () && it->second->identHash != ident->GetIdentHash () && // address changed?
ident->GetSigningKeyType () != i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) // don't replace by DSA ident->GetSigningKeyType () != i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) // don't replace by DSA
{ {
it->second->identHash = ident->GetIdentHash (); it->second->identHash = ident->GetIdentHash ();
m_Storage->AddAddress (ident); m_Storage->AddAddress (ident);

View File

@ -660,7 +660,7 @@ namespace client
else else
SendReplyError ("Local LeaseSet Not found"); SendReplyError ("Local LeaseSet Not found");
} }
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len) void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: clear"); LogPrint (eLogDebug, "BOB: clear");
@ -786,7 +786,7 @@ namespace client
m_CommandHandlers[BOB_COMMAND_INPORT] = &BOBCommandSession::InportCommandHandler; m_CommandHandlers[BOB_COMMAND_INPORT] = &BOBCommandSession::InportCommandHandler;
m_CommandHandlers[BOB_COMMAND_QUIET] = &BOBCommandSession::QuietCommandHandler; m_CommandHandlers[BOB_COMMAND_QUIET] = &BOBCommandSession::QuietCommandHandler;
m_CommandHandlers[BOB_COMMAND_LOOKUP] = &BOBCommandSession::LookupCommandHandler; m_CommandHandlers[BOB_COMMAND_LOOKUP] = &BOBCommandSession::LookupCommandHandler;
m_CommandHandlers[BOB_COMMAND_LOOKUP_LOCAL] = &BOBCommandSession::LookupLocalCommandHandler; m_CommandHandlers[BOB_COMMAND_LOOKUP_LOCAL] = &BOBCommandSession::LookupLocalCommandHandler;
m_CommandHandlers[BOB_COMMAND_CLEAR] = &BOBCommandSession::ClearCommandHandler; m_CommandHandlers[BOB_COMMAND_CLEAR] = &BOBCommandSession::ClearCommandHandler;
m_CommandHandlers[BOB_COMMAND_LIST] = &BOBCommandSession::ListCommandHandler; m_CommandHandlers[BOB_COMMAND_LIST] = &BOBCommandSession::ListCommandHandler;
m_CommandHandlers[BOB_COMMAND_OPTION] = &BOBCommandSession::OptionCommandHandler; m_CommandHandlers[BOB_COMMAND_OPTION] = &BOBCommandSession::OptionCommandHandler;

View File

@ -406,7 +406,7 @@ namespace client
void ClientContext::CreateNewSharedLocalDestination () void ClientContext::CreateNewSharedLocalDestination ()
{ {
std::map<std::string, std::string> params std::map<std::string, std::string> params
{ {
{ I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, "3" }, { I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, "3" },
{ I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, "3" }, { I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, "3" },
@ -720,10 +720,10 @@ namespace client
std::shared_ptr<ClientDestination> localDestination = nullptr; std::shared_ptr<ClientDestination> localDestination = nullptr;
auto it = destinations.find (keys); auto it = destinations.find (keys);
if (it != destinations.end ()) if (it != destinations.end ())
{ {
localDestination = it->second; localDestination = it->second;
localDestination->SetPublic (true); localDestination->SetPublic (true);
} }
else else
{ {
i2p::data::PrivateKeys k; i2p::data::PrivateKeys k;
@ -767,10 +767,10 @@ namespace client
LogPrint(eLogInfo, "Clients: I2P Server Forward created for UDP Endpoint ", host, ":", port, " bound on ", address, " for ",localDestination->GetIdentHash().ToBase32()); LogPrint(eLogInfo, "Clients: I2P Server Forward created for UDP Endpoint ", host, ":", port, " bound on ", address, " for ",localDestination->GetIdentHash().ToBase32());
} }
else else
{ {
ins.first->second->isUpdated = true; ins.first->second->isUpdated = true;
LogPrint(eLogError, "Clients: I2P Server Forward for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash()), "/", port, " already exists"); LogPrint(eLogError, "Clients: I2P Server Forward for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash()), "/", port, " already exists");
} }
continue; continue;
} }

View File

@ -107,7 +107,7 @@ namespace client
// i18n // i18n
std::shared_ptr<const i2p::i18n::Locale> GetLanguage () { return m_Language; }; std::shared_ptr<const i2p::i18n::Locale> GetLanguage () { return m_Language; };
void SetLanguage (const std::shared_ptr<const i2p::i18n::Locale> language) { m_Language = language; }; void SetLanguage (const std::shared_ptr<const i2p::i18n::Locale> language) { m_Language = language; };
private: private:
void ReadTunnels (); void ReadTunnels ();
@ -157,7 +157,7 @@ namespace client
// i18n // i18n
std::shared_ptr<const i2p::i18n::Locale> m_Language; std::shared_ptr<const i2p::i18n::Locale> m_Language;
public: public:
// for HTTP // for HTTP

View File

@ -23,7 +23,7 @@ namespace i2p
namespace client namespace client
{ {
I2CPDestination::I2CPDestination (boost::asio::io_service& service, std::shared_ptr<I2CPSession> owner, I2CPDestination::I2CPDestination (boost::asio::io_service& service, std::shared_ptr<I2CPSession> owner,
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params): std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params):
LeaseSetDestination (service, isPublic, &params), LeaseSetDestination (service, isPublic, &params),
m_Owner (owner), m_Identity (identity), m_EncryptionKeyType (m_Identity->GetCryptoKeyType ()), m_Owner (owner), m_Identity (identity), m_EncryptionKeyType (m_Identity->GetCryptoKeyType ()),
@ -36,8 +36,8 @@ namespace client
LeaseSetDestination::Stop (); LeaseSetDestination::Stop ();
m_Owner = nullptr; m_Owner = nullptr;
m_LeaseSetCreationTimer.cancel (); m_LeaseSetCreationTimer.cancel ();
} }
void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key) void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key)
{ {
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_Identity->GetCryptoKeyType (), key); m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_Identity->GetCryptoKeyType (), key);
@ -46,12 +46,12 @@ namespace client
void I2CPDestination::SetECIESx25519EncryptionPrivateKey (const uint8_t * key) void I2CPDestination::SetECIESx25519EncryptionPrivateKey (const uint8_t * key)
{ {
if (!m_ECIESx25519Decryptor || memcmp (m_ECIESx25519PrivateKey, key, 32)) // new key? if (!m_ECIESx25519Decryptor || memcmp (m_ECIESx25519PrivateKey, key, 32)) // new key?
{ {
m_ECIESx25519Decryptor = std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key, true); // calculate public m_ECIESx25519Decryptor = std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key, true); // calculate public
memcpy (m_ECIESx25519PrivateKey, key, 32); memcpy (m_ECIESx25519PrivateKey, key, 32);
} }
} }
bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const
{ {
if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && m_ECIESx25519Decryptor) if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && m_ECIESx25519Decryptor)
@ -68,14 +68,14 @@ namespace client
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && m_ECIESx25519Decryptor) if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && m_ECIESx25519Decryptor)
return m_ECIESx25519Decryptor->GetPubicKey (); return m_ECIESx25519Decryptor->GetPubicKey ();
return nullptr; return nullptr;
}
bool I2CPDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const
{
return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? (bool)m_ECIESx25519Decryptor : m_EncryptionKeyType == keyType;
} }
bool I2CPDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const
{
return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? (bool)m_ECIESx25519Decryptor : m_EncryptionKeyType == keyType;
}
void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len) void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len)
{ {
uint32_t length = bufbe32toh (buf); uint32_t length = bufbe32toh (buf);
@ -88,25 +88,25 @@ namespace client
{ {
GetService ().post (std::bind (&I2CPDestination::PostCreateNewLeaseSet, this, tunnels)); GetService ().post (std::bind (&I2CPDestination::PostCreateNewLeaseSet, this, tunnels));
} }
void I2CPDestination::PostCreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels) void I2CPDestination::PostCreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels)
{ {
if (m_IsCreatingLeaseSet) if (m_IsCreatingLeaseSet)
{ {
LogPrint (eLogInfo, "I2CP: LeaseSet is being created"); LogPrint (eLogInfo, "I2CP: LeaseSet is being created");
return; return;
} }
uint8_t priv[256] = {0}; uint8_t priv[256] = {0};
i2p::data::LocalLeaseSet ls (m_Identity, priv, tunnels); // we don't care about encryption key, we need leases only i2p::data::LocalLeaseSet ls (m_Identity, priv, tunnels); // we don't care about encryption key, we need leases only
m_LeaseSetExpirationTime = ls.GetExpirationTime (); m_LeaseSetExpirationTime = ls.GetExpirationTime ();
uint8_t * leases = ls.GetLeases (); uint8_t * leases = ls.GetLeases ();
leases[-1] = tunnels.size (); leases[-1] = tunnels.size ();
if (m_Owner) if (m_Owner)
{ {
uint16_t sessionID = m_Owner->GetSessionID (); uint16_t sessionID = m_Owner->GetSessionID ();
if (sessionID != 0xFFFF) if (sessionID != 0xFFFF)
{ {
m_IsCreatingLeaseSet = true; m_IsCreatingLeaseSet = true;
htobe16buf (leases - 3, sessionID); htobe16buf (leases - 3, sessionID);
size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size (); size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size ();
m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l); m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l);
@ -120,8 +120,8 @@ namespace client
if (s->m_Owner) s->m_Owner->Stop (); if (s->m_Owner) s->m_Owner->Stop ();
} }
}); });
} }
} }
} }
void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len) void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len)
@ -237,18 +237,18 @@ namespace client
} }
} }
RunnableI2CPDestination::RunnableI2CPDestination (std::shared_ptr<I2CPSession> owner, RunnableI2CPDestination::RunnableI2CPDestination (std::shared_ptr<I2CPSession> owner,
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params): std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params):
RunnableService ("I2CP"), RunnableService ("I2CP"),
I2CPDestination (GetIOService (), owner, identity, isPublic, params) I2CPDestination (GetIOService (), owner, identity, isPublic, params)
{ {
} }
RunnableI2CPDestination::~RunnableI2CPDestination () RunnableI2CPDestination::~RunnableI2CPDestination ()
{ {
if (IsRunning ()) if (IsRunning ())
Stop (); Stop ();
} }
void RunnableI2CPDestination::Start () void RunnableI2CPDestination::Start ()
{ {
@ -267,9 +267,9 @@ namespace client
StopIOService (); StopIOService ();
} }
} }
I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<proto::socket> socket): I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<proto::socket> socket):
m_Owner (owner), m_Socket (socket), m_SessionID (0xFFFF), m_Owner (owner), m_Socket (socket), m_SessionID (0xFFFF),
m_MessageID (0), m_IsSendAccepted (true), m_IsSending (false) m_MessageID (0), m_IsSendAccepted (true), m_IsSending (false)
{ {
} }
@ -307,11 +307,11 @@ namespace client
void I2CPSession::ReceiveHeader () void I2CPSession::ReceiveHeader ()
{ {
if (!m_Socket) if (!m_Socket)
{ {
LogPrint (eLogError, "I2CP: Can't receive header"); LogPrint (eLogError, "I2CP: Can't receive header");
return; return;
} }
boost::asio::async_read (*m_Socket, boost::asio::buffer (m_Header, I2CP_HEADER_SIZE), boost::asio::async_read (*m_Socket, boost::asio::buffer (m_Header, I2CP_HEADER_SIZE),
boost::asio::transfer_all (), boost::asio::transfer_all (),
std::bind (&I2CPSession::HandleReceivedHeader, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); std::bind (&I2CPSession::HandleReceivedHeader, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
@ -344,11 +344,11 @@ namespace client
void I2CPSession::ReceivePayload () void I2CPSession::ReceivePayload ()
{ {
if (!m_Socket) if (!m_Socket)
{ {
LogPrint (eLogError, "I2CP: Can't receive payload"); LogPrint (eLogError, "I2CP: Can't receive payload");
return; return;
} }
boost::asio::async_read (*m_Socket, boost::asio::buffer (m_Payload, m_PayloadLen), boost::asio::async_read (*m_Socket, boost::asio::buffer (m_Payload, m_PayloadLen),
boost::asio::transfer_all (), boost::asio::transfer_all (),
std::bind (&I2CPSession::HandleReceivedPayload, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); std::bind (&I2CPSession::HandleReceivedPayload, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
@ -390,11 +390,11 @@ namespace client
if (!m_SendQueue.IsEmpty ()) if (!m_SendQueue.IsEmpty ())
m_SendQueue.CleanUp (); m_SendQueue.CleanUp ();
if (m_SessionID != 0xFFFF) if (m_SessionID != 0xFFFF)
{ {
m_Owner.RemoveSession (GetSessionID ()); m_Owner.RemoveSession (GetSessionID ());
LogPrint (eLogDebug, "I2CP: Session ", m_SessionID, " terminated"); LogPrint (eLogDebug, "I2CP: Session ", m_SessionID, " terminated");
m_SessionID = 0xFFFF; m_SessionID = 0xFFFF;
} }
} }
void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len) void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len)
@ -404,39 +404,39 @@ namespace client
{ {
LogPrint (eLogError, "I2CP: Message to send is too long ", l); LogPrint (eLogError, "I2CP: Message to send is too long ", l);
return; return;
} }
auto sendBuf = m_IsSending ? std::make_shared<i2p::stream::SendBuffer> (l) : nullptr; auto sendBuf = m_IsSending ? std::make_shared<i2p::stream::SendBuffer> (l) : nullptr;
uint8_t * buf = sendBuf ? sendBuf->buf : m_SendBuffer; uint8_t * buf = sendBuf ? sendBuf->buf : m_SendBuffer;
htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len); htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len);
buf[I2CP_HEADER_TYPE_OFFSET] = type; buf[I2CP_HEADER_TYPE_OFFSET] = type;
memcpy (buf + I2CP_HEADER_SIZE, payload, len); memcpy (buf + I2CP_HEADER_SIZE, payload, len);
if (sendBuf) if (sendBuf)
{ {
if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE) if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE)
m_SendQueue.Add (sendBuf); m_SendQueue.Add (sendBuf);
else else
{ {
LogPrint (eLogWarning, "I2CP: Send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); LogPrint (eLogWarning, "I2CP: Send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE);
return; return;
} }
} }
else else
{ {
auto socket = m_Socket; auto socket = m_Socket;
if (socket) if (socket)
{ {
m_IsSending = true; m_IsSending = true;
boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l), boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l),
boost::asio::transfer_all (), std::bind(&I2CPSession::HandleI2CPMessageSent, boost::asio::transfer_all (), std::bind(&I2CPSession::HandleI2CPMessageSent,
shared_from_this (), std::placeholders::_1, std::placeholders::_2)); shared_from_this (), std::placeholders::_1, std::placeholders::_2));
} }
} }
} }
void I2CPSession::HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) void I2CPSession::HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{ {
if (ecode) if (ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
@ -444,19 +444,19 @@ namespace client
{ {
auto socket = m_Socket; auto socket = m_Socket;
if (socket) if (socket)
{ {
auto len = m_SendQueue.Get (m_SendBuffer, I2CP_MAX_MESSAGE_LENGTH); auto len = m_SendQueue.Get (m_SendBuffer, I2CP_MAX_MESSAGE_LENGTH);
boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, len), boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, len),
boost::asio::transfer_all (),std::bind(&I2CPSession::HandleI2CPMessageSent, boost::asio::transfer_all (),std::bind(&I2CPSession::HandleI2CPMessageSent,
shared_from_this (), std::placeholders::_1, std::placeholders::_2)); shared_from_this (), std::placeholders::_1, std::placeholders::_2));
} }
else else
m_IsSending = false; m_IsSending = false;
} }
else else
m_IsSending = false; m_IsSending = false;
} }
std::string I2CPSession::ExtractString (const uint8_t * buf, size_t len) std::string I2CPSession::ExtractString (const uint8_t * buf, size_t len)
{ {
uint8_t l = buf[0]; uint8_t l = buf[0];
@ -699,12 +699,12 @@ namespace client
m_Destination->SetECIESx25519EncryptionPrivateKey (buf + offset); m_Destination->SetECIESx25519EncryptionPrivateKey (buf + offset);
else else
{ {
m_Destination->SetEncryptionType (keyType); m_Destination->SetEncryptionType (keyType);
m_Destination->SetEncryptionPrivateKey (buf + offset); m_Destination->SetEncryptionPrivateKey (buf + offset);
} }
offset += keyLen; offset += keyLen;
} }
m_Destination->LeaseSet2Created (storeType, ls.GetBuffer (), ls.GetBufferLen ()); m_Destination->LeaseSet2Created (storeType, ls.GetBuffer (), ls.GetBufferLen ());
} }
} }
@ -885,7 +885,7 @@ namespace client
{ {
LogPrint (eLogError, "I2CP: Message to send is too long ", l); LogPrint (eLogError, "I2CP: Message to send is too long ", l);
return; return;
} }
auto sendBuf = m_IsSending ? std::make_shared<i2p::stream::SendBuffer> (l) : nullptr; auto sendBuf = m_IsSending ? std::make_shared<i2p::stream::SendBuffer> (l) : nullptr;
uint8_t * buf = sendBuf ? sendBuf->buf : m_SendBuffer; uint8_t * buf = sendBuf ? sendBuf->buf : m_SendBuffer;
htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10); htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10);
@ -895,26 +895,26 @@ namespace client
htobe32buf (buf + I2CP_HEADER_SIZE + 6, len); htobe32buf (buf + I2CP_HEADER_SIZE + 6, len);
memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len); memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len);
if (sendBuf) if (sendBuf)
{ {
if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE) if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE)
m_SendQueue.Add (sendBuf); m_SendQueue.Add (sendBuf);
else else
{ {
LogPrint (eLogWarning, "I2CP: Send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); LogPrint (eLogWarning, "I2CP: Send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE);
return; return;
} }
} }
else else
{ {
auto socket = m_Socket; auto socket = m_Socket;
if (socket) if (socket)
{ {
m_IsSending = true; m_IsSending = true;
boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l), boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l),
boost::asio::transfer_all (), std::bind(&I2CPSession::HandleI2CPMessageSent, boost::asio::transfer_all (), std::bind(&I2CPSession::HandleI2CPMessageSent,
shared_from_this (), std::placeholders::_1, std::placeholders::_2)); shared_from_this (), std::placeholders::_1, std::placeholders::_2));
} }
} }
} }
I2CPServer::I2CPServer (const std::string& interface, int port, bool isSingleThread): I2CPServer::I2CPServer (const std::string& interface, int port, bool isSingleThread):

View File

@ -27,8 +27,8 @@ namespace client
const size_t I2CP_SESSION_BUFFER_SIZE = 4096; const size_t I2CP_SESSION_BUFFER_SIZE = 4096;
const size_t I2CP_MAX_MESSAGE_LENGTH = 65535; const size_t I2CP_MAX_MESSAGE_LENGTH = 65535;
const size_t I2CP_MAX_SEND_QUEUE_SIZE = 1024*1024; // in bytes, 1M const size_t I2CP_MAX_SEND_QUEUE_SIZE = 1024*1024; // in bytes, 1M
const int I2CP_LEASESET_CREATION_TIMEOUT = 10; // in seconds const int I2CP_LEASESET_CREATION_TIMEOUT = 10; // in seconds
const size_t I2CP_HEADER_LENGTH_OFFSET = 0; const size_t I2CP_HEADER_LENGTH_OFFSET = 0;
const size_t I2CP_HEADER_TYPE_OFFSET = I2CP_HEADER_LENGTH_OFFSET + 4; const size_t I2CP_HEADER_TYPE_OFFSET = I2CP_HEADER_LENGTH_OFFSET + 4;
const size_t I2CP_HEADER_SIZE = I2CP_HEADER_TYPE_OFFSET + 1; const size_t I2CP_HEADER_SIZE = I2CP_HEADER_TYPE_OFFSET + 1;
@ -69,12 +69,12 @@ namespace client
{ {
public: public:
I2CPDestination (boost::asio::io_service& service, std::shared_ptr<I2CPSession> owner, I2CPDestination (boost::asio::io_service& service, std::shared_ptr<I2CPSession> owner,
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params); std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params);
~I2CPDestination () {}; ~I2CPDestination () {};
void Stop (); void Stop ();
void SetEncryptionPrivateKey (const uint8_t * key); void SetEncryptionPrivateKey (const uint8_t * key);
void SetEncryptionType (i2p::data::CryptoKeyType keyType) { m_EncryptionKeyType = keyType; }; void SetEncryptionType (i2p::data::CryptoKeyType keyType) { m_EncryptionKeyType = keyType; };
void SetECIESx25519EncryptionPrivateKey (const uint8_t * key); void SetECIESx25519EncryptionPrivateKey (const uint8_t * key);
@ -84,7 +84,7 @@ namespace client
// implements LocalDestination // implements LocalDestination
bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const; bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const;
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const; bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const;
const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const; // for 4 only const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const; // for 4 only
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Identity; }; std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Identity; };
@ -101,7 +101,7 @@ namespace client
bool SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote); bool SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
void PostCreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels); void PostCreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
private: private:
std::shared_ptr<I2CPSession> m_Owner; std::shared_ptr<I2CPSession> m_Owner;
@ -115,18 +115,18 @@ namespace client
boost::asio::deadline_timer m_LeaseSetCreationTimer; boost::asio::deadline_timer m_LeaseSetCreationTimer;
}; };
class RunnableI2CPDestination: private i2p::util::RunnableService, public I2CPDestination class RunnableI2CPDestination: private i2p::util::RunnableService, public I2CPDestination
{ {
public: public:
RunnableI2CPDestination (std::shared_ptr<I2CPSession> owner, std::shared_ptr<const i2p::data::IdentityEx> identity, RunnableI2CPDestination (std::shared_ptr<I2CPSession> owner, std::shared_ptr<const i2p::data::IdentityEx> identity,
bool isPublic, const std::map<std::string, std::string>& params); bool isPublic, const std::map<std::string, std::string>& params);
~RunnableI2CPDestination (); ~RunnableI2CPDestination ();
void Start (); void Start ();
void Stop (); void Stop ();
}; };
class I2CPServer; class I2CPServer;
class I2CPSession: public std::enable_shared_from_this<I2CPSession> class I2CPSession: public std::enable_shared_from_this<I2CPSession>
{ {
@ -174,9 +174,9 @@ namespace client
void HandleReceivedPayload (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleReceivedPayload (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleMessage (); void HandleMessage ();
void Terminate (); void Terminate ();
void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
std::string ExtractString (const uint8_t * buf, size_t len); std::string ExtractString (const uint8_t * buf, size_t len);
size_t PutString (uint8_t * buf, size_t len, const std::string& str); size_t PutString (uint8_t * buf, size_t len, const std::string& str);
void ExtractMapping (const uint8_t * buf, size_t len, std::map<std::string, std::string>& mapping); void ExtractMapping (const uint8_t * buf, size_t len, std::map<std::string, std::string>& mapping);
@ -198,7 +198,7 @@ namespace client
// to client // to client
bool m_IsSending; bool m_IsSending;
uint8_t m_SendBuffer[I2CP_MAX_MESSAGE_LENGTH]; uint8_t m_SendBuffer[I2CP_MAX_MESSAGE_LENGTH];
i2p::stream::SendBufferQueue m_SendQueue; i2p::stream::SendBufferQueue m_SendQueue;
}; };
typedef void (I2CPSession::*I2CPMessageHandler)(const uint8_t * buf, size_t len); typedef void (I2CPSession::*I2CPMessageHandler)(const uint8_t * buf, size_t len);
@ -213,7 +213,7 @@ namespace client
void Stop (); void Stop ();
boost::asio::io_service& GetService () { return GetIOService (); }; boost::asio::io_service& GetService () { return GetIOService (); };
bool IsSingleThread () const { return m_IsSingleThread; }; bool IsSingleThread () const { return m_IsSingleThread; };
bool InsertSession (std::shared_ptr<I2CPSession> session); bool InsertSession (std::shared_ptr<I2CPSession> session);
void RemoveSession (uint16_t sessionID); void RemoveSession (uint16_t sessionID);

View File

@ -87,7 +87,7 @@ namespace client
boost::system::error_code ec; boost::system::error_code ec;
sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0), ec); sock->bind (boost::asio::ip::tcp::endpoint (ourIP, 0), ec);
if (ec) if (ec)
LogPrint (eLogError, "I2PTunnel: Can't bind ourIP to ", ourIP.to_string (), ": ", ec.message ()); LogPrint (eLogError, "I2PTunnel: Can't bind ourIP to ", ourIP.to_string (), ": ", ec.message ());
} }
#endif #endif
@ -122,11 +122,11 @@ namespace client
boost::system::error_code ec; boost::system::error_code ec;
m_Socket->bind (boost::asio::ip::tcp::endpoint (localAddress, 0), ec); m_Socket->bind (boost::asio::ip::tcp::endpoint (localAddress, 0), ec);
if (ec) if (ec)
LogPrint (eLogError, "I2PTunnel: Can't bind to ", localAddress.to_string (), ": ", ec.message ()); LogPrint (eLogError, "I2PTunnel: Can't bind to ", localAddress.to_string (), ": ", ec.message ());
} }
Connect (false); Connect (false);
} }
void I2PTunnelConnection::Terminate () void I2PTunnelConnection::Terminate ()
{ {
if (Kill()) return; if (Kill()) return;
@ -177,8 +177,8 @@ namespace client
s->Terminate (); s->Terminate ();
}); });
} }
} }
void I2PTunnelConnection::HandleWrite (const boost::system::error_code& ecode) void I2PTunnelConnection::HandleWrite (const boost::system::error_code& ecode)
{ {
if (ecode) if (ecode)
@ -326,7 +326,7 @@ namespace client
I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, I2PServerTunnelConnectionHTTP::I2PServerTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, const std::string& host): const boost::asio::ip::tcp::endpoint& target, const std::string& host):
I2PTunnelConnection (owner, stream, socket, target), m_Host (host), I2PTunnelConnection (owner, stream, socket, target), m_Host (host),
m_HeaderSent (false), m_ResponseHeaderSent (false), m_From (stream->GetRemoteIdentity ()) m_HeaderSent (false), m_ResponseHeaderSent (false), m_From (stream->GetRemoteIdentity ())
{ {
} }
@ -368,7 +368,7 @@ namespace client
m_OutHeader << X_I2P_DEST_HASH << ": " << m_From->GetIdentHash ().ToBase64 () << "\r\n"; m_OutHeader << X_I2P_DEST_HASH << ": " << m_From->GetIdentHash ().ToBase64 () << "\r\n";
m_OutHeader << X_I2P_DEST_B64 << ": " << m_From->ToBase64 () << "\r\n"; m_OutHeader << X_I2P_DEST_B64 << ": " << m_From->ToBase64 () << "\r\n";
} }
m_OutHeader << "\r\n"; // end of header m_OutHeader << "\r\n"; // end of header
m_OutHeader << m_InHeader.str ().substr (m_InHeader.tellg ()); // data right after header m_OutHeader << m_InHeader.str ().substr (m_InHeader.tellg ()); // data right after header
m_InHeader.str (""); m_InHeader.str ("");
@ -404,11 +404,11 @@ namespace client
}; };
bool matched = false; bool matched = false;
for (const auto& it: excluded) for (const auto& it: excluded)
if (!line.compare(0, it.length (), it)) if (!line.compare(0, it.length (), it))
{ {
matched = true; matched = true;
break; break;
} }
if (!matched) if (!matched)
m_OutHeader << line << "\n"; m_OutHeader << line << "\n";
} }
@ -425,12 +425,12 @@ namespace client
m_ResponseHeaderSent = true; m_ResponseHeaderSent = true;
I2PTunnelConnection::WriteToStream ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ()); I2PTunnelConnection::WriteToStream ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
m_OutHeader.str (""); m_OutHeader.str ("");
} }
else else
Receive (); Receive ();
} }
} }
I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, I2PTunnelConnectionIRC::I2PTunnelConnectionIRC (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass): const boost::asio::ip::tcp::endpoint& target, const std::string& webircpass):
@ -556,8 +556,8 @@ namespace client
m_KeepAliveInterval = keepAliveInterval; m_KeepAliveInterval = keepAliveInterval;
if (m_KeepAliveInterval) if (m_KeepAliveInterval)
m_KeepAliveTimer.reset (new boost::asio::deadline_timer (GetLocalDestination ()->GetService ())); m_KeepAliveTimer.reset (new boost::asio::deadline_timer (GetLocalDestination ()->GetService ()));
} }
/* HACK: maybe we should create a caching IdentHash provider in AddressBook */ /* HACK: maybe we should create a caching IdentHash provider in AddressBook */
std::shared_ptr<const Address> I2PClientTunnel::GetAddress () std::shared_ptr<const Address> I2PClientTunnel::GetAddress ()
{ {
@ -586,24 +586,24 @@ namespace client
m_KeepAliveTimer->expires_from_now (boost::posix_time::seconds(m_KeepAliveInterval)); m_KeepAliveTimer->expires_from_now (boost::posix_time::seconds(m_KeepAliveInterval));
m_KeepAliveTimer->async_wait (std::bind (&I2PClientTunnel::HandleKeepAliveTimer, m_KeepAliveTimer->async_wait (std::bind (&I2PClientTunnel::HandleKeepAliveTimer,
this, std::placeholders::_1)); this, std::placeholders::_1));
} }
} }
void I2PClientTunnel::HandleKeepAliveTimer (const boost::system::error_code& ecode) void I2PClientTunnel::HandleKeepAliveTimer (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
if (m_Address && m_Address->IsValid ()) if (m_Address && m_Address->IsValid ())
{ {
if (m_Address->IsIdentHash ()) if (m_Address->IsIdentHash ())
GetLocalDestination ()->SendPing (m_Address->identHash); GetLocalDestination ()->SendPing (m_Address->identHash);
else else
GetLocalDestination ()->SendPing (m_Address->blindedPublicKey); GetLocalDestination ()->SendPing (m_Address->blindedPublicKey);
} }
ScheduleKeepAliveTimer (); ScheduleKeepAliveTimer ();
} }
} }
I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address, I2PServerTunnel::I2PServerTunnel (const std::string& name, const std::string& address,
int port, std::shared_ptr<ClientDestination> localDestination, int inport, bool gzip): int port, std::shared_ptr<ClientDestination> localDestination, int inport, bool gzip):
I2PService (localDestination), m_IsUniqueLocal(true), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false) I2PService (localDestination), m_IsUniqueLocal(true), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false)
@ -643,16 +643,16 @@ namespace client
bool found = false; bool found = false;
boost::asio::ip::tcp::endpoint ep; boost::asio::ip::tcp::endpoint ep;
if (m_LocalAddress) if (m_LocalAddress)
{ {
boost::asio::ip::tcp::resolver::iterator end; boost::asio::ip::tcp::resolver::iterator end;
while (it != end) while (it != end)
{ {
ep = *it; ep = *it;
if (!ep.address ().is_unspecified ()) if (!ep.address ().is_unspecified ())
{ {
if (ep.address ().is_v4 ()) if (ep.address ().is_v4 ())
{ {
if (m_LocalAddress->is_v4 ()) found = true; if (m_LocalAddress->is_v4 ()) found = true;
} }
else if (ep.address ().is_v6 ()) else if (ep.address ().is_v6 ())
{ {
@ -660,26 +660,26 @@ namespace client
{ {
if (i2p::util::net::IsYggdrasilAddress (*m_LocalAddress)) if (i2p::util::net::IsYggdrasilAddress (*m_LocalAddress))
found = true; found = true;
} }
else if (m_LocalAddress->is_v6 ()) else if (m_LocalAddress->is_v6 ())
found = true; found = true;
} }
} }
if (found) break; if (found) break;
it++; it++;
} }
} }
else else
{ {
found = true; found = true;
ep = *it; // first available ep = *it; // first available
} }
if (!found) if (!found)
{ {
LogPrint (eLogError, "I2PTunnel: Unable to resolve to compatible address"); LogPrint (eLogError, "I2PTunnel: Unable to resolve to compatible address");
return; return;
} }
auto addr = ep.address (); auto addr = ep.address ();
LogPrint (eLogInfo, "I2PTunnel: Server tunnel ", (*it).host_name (), " has been resolved to ", addr); LogPrint (eLogInfo, "I2PTunnel: Server tunnel ", (*it).host_name (), " has been resolved to ", addr);
m_Endpoint.address (addr); m_Endpoint.address (addr);
@ -703,8 +703,8 @@ namespace client
m_LocalAddress.reset (new boost::asio::ip::address (addr)); m_LocalAddress.reset (new boost::asio::ip::address (addr));
else else
LogPrint (eLogError, "I2PTunnel: Can't set local address ", localAddress); LogPrint (eLogError, "I2PTunnel: Can't set local address ", localAddress);
} }
void I2PServerTunnel::Accept () void I2PServerTunnel::Accept ()
{ {
if (m_PortDestination) if (m_PortDestination)
@ -738,7 +738,7 @@ namespace client
AddHandler (conn); AddHandler (conn);
if (m_LocalAddress) if (m_LocalAddress)
conn->Connect (*m_LocalAddress); conn->Connect (*m_LocalAddress);
else else
conn->Connect (m_IsUniqueLocal); conn->Connect (m_IsUniqueLocal);
} }
} }
@ -793,9 +793,9 @@ namespace client
{ {
m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint); m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint);
m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch(); m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch();
} }
} }
void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) { void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) {
std::lock_guard<std::mutex> lock(m_SessionsMutex); std::lock_guard<std::mutex> lock(m_SessionsMutex);
uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
@ -883,20 +883,20 @@ namespace client
m_Destination->SendRawDatagram(session, m_Buffer, len, LocalPort, RemotePort); m_Destination->SendRawDatagram(session, m_Buffer, len, LocalPort, RemotePort);
size_t numPackets = 0; size_t numPackets = 0;
while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE) while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE)
{ {
boost::system::error_code ec; boost::system::error_code ec;
size_t moreBytes = IPSocket.available(ec); size_t moreBytes = IPSocket.available(ec);
if (ec || !moreBytes) break; if (ec || !moreBytes) break;
len = IPSocket.receive_from (boost::asio::buffer (m_Buffer, I2P_UDP_MAX_MTU), FromEndpoint, 0, ec); len = IPSocket.receive_from (boost::asio::buffer (m_Buffer, I2P_UDP_MAX_MTU), FromEndpoint, 0, ec);
m_Destination->SendRawDatagram (session, m_Buffer, len, LocalPort, RemotePort); m_Destination->SendRawDatagram (session, m_Buffer, len, LocalPort, RemotePort);
numPackets++; numPackets++;
} }
if (numPackets > 0) if (numPackets > 0)
LogPrint(eLogDebug, "UDPSession: Forward more ", numPackets, "packets B from ", FromEndpoint); LogPrint(eLogDebug, "UDPSession: Forward more ", numPackets, "packets B from ", FromEndpoint);
m_Destination->FlushSendQueue (session); m_Destination->FlushSendQueue (session);
LastActivity = ts; LastActivity = ts;
Receive(); Receive();
} }
else else
LogPrint(eLogError, "UDPSession: ", ecode.message()); LogPrint(eLogError, "UDPSession: ", ecode.message());
} }
@ -912,7 +912,7 @@ namespace client
m_LocalDest->Start(); m_LocalDest->Start();
auto dgram = m_LocalDest->CreateDatagramDestination(gzip); auto dgram = m_LocalDest->CreateDatagramDestination(gzip);
dgram->SetReceiver(std::bind(&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); dgram->SetReceiver(std::bind(&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
dgram->SetRawReceiver(std::bind(&I2PUDPServerTunnel::HandleRecvFromI2PRaw, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); dgram->SetRawReceiver(std::bind(&I2PUDPServerTunnel::HandleRecvFromI2PRaw, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
} }
I2PUDPServerTunnel::~I2PUDPServerTunnel() I2PUDPServerTunnel::~I2PUDPServerTunnel()
@ -1011,9 +1011,9 @@ namespace client
{ {
m_LastSession = std::make_shared<UDPConvo>(boost::asio::ip::udp::endpoint(m_RecvEndpoint), 0); m_LastSession = std::make_shared<UDPConvo>(boost::asio::ip::udp::endpoint(m_RecvEndpoint), 0);
m_Sessions.emplace (remotePort, m_LastSession); m_Sessions.emplace (remotePort, m_LastSession);
} }
m_LastPort = remotePort; m_LastPort = remotePort;
} }
// send off to remote i2p destination // send off to remote i2p destination
auto ts = i2p::util::GetMillisecondsSinceEpoch(); auto ts = i2p::util::GetMillisecondsSinceEpoch();
LogPrint(eLogDebug, "UDP Client: Send ", transferred, " to ", m_RemoteIdent->ToBase32(), ":", RemotePort); LogPrint(eLogDebug, "UDP Client: Send ", transferred, " to ", m_RemoteIdent->ToBase32(), ":", RemotePort);
@ -1024,20 +1024,20 @@ namespace client
m_LocalDest->GetDatagramDestination()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort); m_LocalDest->GetDatagramDestination()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
size_t numPackets = 0; size_t numPackets = 0;
while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE) while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE)
{ {
boost::system::error_code ec; boost::system::error_code ec;
size_t moreBytes = m_LocalSocket.available(ec); size_t moreBytes = m_LocalSocket.available(ec);
if (ec || !moreBytes) break; if (ec || !moreBytes) break;
transferred = m_LocalSocket.receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU), m_RecvEndpoint, 0, ec); transferred = m_LocalSocket.receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU), m_RecvEndpoint, 0, ec);
remotePort = m_RecvEndpoint.port(); remotePort = m_RecvEndpoint.port();
// TODO: check remotePort // TODO: check remotePort
m_LocalDest->GetDatagramDestination()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort); m_LocalDest->GetDatagramDestination()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
numPackets++; numPackets++;
} }
if (numPackets) if (numPackets)
LogPrint(eLogDebug, "UDP Client: Sent ", numPackets, " more packets to ", m_RemoteIdent->ToBase32()); LogPrint(eLogDebug, "UDP Client: Sent ", numPackets, " more packets to ", m_RemoteIdent->ToBase32());
m_LocalDest->GetDatagramDestination()->FlushSendQueue (session); m_LocalDest->GetDatagramDestination()->FlushSendQueue (session);
// mark convo as active // mark convo as active
if (m_LastSession) if (m_LastSession)
m_LastSession->second = ts; m_LastSession->second = ts;
@ -1091,7 +1091,7 @@ namespace client
if(itr != m_Sessions.end()) if(itr != m_Sessions.end())
{ {
// found convo // found convo
if (len > 0) if (len > 0)
{ {
LogPrint(eLogDebug, "UDP Client: Got ", len, "B from ", m_RemoteIdent ? m_RemoteIdent->ToBase32() : ""); LogPrint(eLogDebug, "UDP Client: Got ", len, "B from ", m_RemoteIdent ? m_RemoteIdent->ToBase32() : "");
m_LocalSocket.send_to(boost::asio::buffer(buf, len), itr->second->first); m_LocalSocket.send_to(boost::asio::buffer(buf, len), itr->second->first);

View File

@ -49,7 +49,7 @@ namespace client
void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0); void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
void Connect (bool isUniqueLocal = true); void Connect (bool isUniqueLocal = true);
void Connect (const boost::asio::ip::address& localAddress); void Connect (const boost::asio::ip::address& localAddress);
protected: protected:
void Terminate (); void Terminate ();
@ -59,7 +59,7 @@ namespace client
virtual void Write (const uint8_t * buf, size_t len); // can be overloaded virtual void Write (const uint8_t * buf, size_t len); // can be overloaded
void HandleWrite (const boost::system::error_code& ecode); void HandleWrite (const boost::system::error_code& ecode);
virtual void WriteToStream (const uint8_t * buf, size_t len); // can be overloaded virtual void WriteToStream (const uint8_t * buf, size_t len); // can be overloaded
void StreamReceive (); void StreamReceive ();
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleConnect (const boost::system::error_code& ecode); void HandleConnect (const boost::system::error_code& ecode);
@ -105,7 +105,7 @@ namespace client
protected: protected:
void Write (const uint8_t * buf, size_t len); void Write (const uint8_t * buf, size_t len);
void WriteToStream (const uint8_t * buf, size_t len); void WriteToStream (const uint8_t * buf, size_t len);
private: private:
@ -154,11 +154,11 @@ namespace client
const char* GetName() { return m_Name.c_str (); } const char* GetName() { return m_Name.c_str (); }
void SetKeepAliveInterval (uint32_t keepAliveInterval); void SetKeepAliveInterval (uint32_t keepAliveInterval);
private: private:
std::shared_ptr<const Address> GetAddress (); std::shared_ptr<const Address> GetAddress ();
void ScheduleKeepAliveTimer (); void ScheduleKeepAliveTimer ();
void HandleKeepAliveTimer (const boost::system::error_code& ecode); void HandleKeepAliveTimer (const boost::system::error_code& ecode);
@ -174,8 +174,8 @@ namespace client
/** 2 minute timeout for udp sessions */ /** 2 minute timeout for udp sessions */
const uint64_t I2P_UDP_SESSION_TIMEOUT = 1000 * 60 * 2; const uint64_t I2P_UDP_SESSION_TIMEOUT = 1000 * 60 * 2;
const uint64_t I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL = 100; // in milliseconds const uint64_t I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL = 100; // in milliseconds
/** max size for i2p udp */ /** max size for i2p udp */
const size_t I2P_UDP_MAX_MTU = 64*1024; const size_t I2P_UDP_MAX_MTU = 64*1024;
@ -330,7 +330,7 @@ namespace client
bool IsUniqueLocal () const { return m_IsUniqueLocal; } bool IsUniqueLocal () const { return m_IsUniqueLocal; }
void SetLocalAddress (const std::string& localAddress); void SetLocalAddress (const std::string& localAddress);
const std::string& GetAddress() const { return m_Address; } const std::string& GetAddress() const { return m_Address; }
int GetPort () const { return m_Port; }; int GetPort () const { return m_Port; };
uint16_t GetLocalPort () const { return m_PortDestination->GetLocalPort (); }; uint16_t GetLocalPort () const { return m_PortDestination->GetLocalPort (); };

View File

@ -72,7 +72,7 @@ namespace client
bool MatchedTunnelDestination::SelectPeers(i2p::tunnel::Path & path, int hops, bool inbound) bool MatchedTunnelDestination::SelectPeers(i2p::tunnel::Path & path, int hops, bool inbound)
{ {
auto pool = GetTunnelPool(); auto pool = GetTunnelPool();
if(!i2p::tunnel::StandardSelectPeers(path, hops, inbound, if(!i2p::tunnel::StandardSelectPeers(path, hops, inbound,
std::bind(&i2p::tunnel::TunnelPool::SelectNextHop, pool, std::placeholders::_1, std::placeholders::_2))) std::bind(&i2p::tunnel::TunnelPool::SelectNextHop, pool, std::placeholders::_1, std::placeholders::_2)))
return false; return false;
// more here for outbound tunnels // more here for outbound tunnels
@ -86,14 +86,14 @@ namespace client
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases(); auto leases = m_RemoteLeaseSet->GetNonExpiredLeases();
// pick lease // pick lease
std::shared_ptr<i2p::data::RouterInfo> obep; std::shared_ptr<i2p::data::RouterInfo> obep;
while(!obep && leases.size() > 0) while(!obep && leases.size() > 0)
{ {
auto idx = rand() % leases.size(); auto idx = rand() % leases.size();
auto lease = leases[idx]; auto lease = leases[idx];
obep = i2p::data::netdb.FindRouter(lease->tunnelGateway); obep = i2p::data::netdb.FindRouter(lease->tunnelGateway);
leases.erase(leases.begin()+idx); leases.erase(leases.begin()+idx);
} }
if(obep) if(obep)
{ {
path.Add (obep); path.Add (obep);
LogPrint(eLogDebug, "Destination: Found OBEP matching IBGW"); LogPrint(eLogDebug, "Destination: Found OBEP matching IBGW");

View File

@ -54,7 +54,7 @@ namespace client
break; break;
} }
case eSAMSocketTypeAcceptor: case eSAMSocketTypeAcceptor:
case eSAMSocketTypeForward: case eSAMSocketTypeForward:
{ {
if (Session) if (Session)
{ {
@ -481,7 +481,7 @@ namespace client
{ {
SendI2PError ("Socket already in use"); SendI2PError ("Socket already in use");
return; return;
} }
std::map<std::string, std::string> params; std::map<std::string, std::string> params;
ExtractParams (buf, params); ExtractParams (buf, params);
std::string& id = params[SAM_PARAM_ID]; std::string& id = params[SAM_PARAM_ID];
@ -502,7 +502,7 @@ namespace client
std::shared_ptr<const Address> addr; std::shared_ptr<const Address> addr;
if (destination.find(".i2p") != std::string::npos) if (destination.find(".i2p") != std::string::npos)
addr = context.GetAddressBook().GetAddress (destination); addr = context.GetAddressBook().GetAddress (destination);
else else
{ {
auto dest = std::make_shared<i2p::data::IdentityEx> (); auto dest = std::make_shared<i2p::data::IdentityEx> ();
@ -511,13 +511,13 @@ namespace client
{ {
context.GetAddressBook().InsertFullAddress(dest); context.GetAddressBook().InsertFullAddress(dest);
addr = std::make_shared<Address>(dest->GetIdentHash ()); addr = std::make_shared<Address>(dest->GetIdentHash ());
} }
} }
if (addr && addr->IsValid ()) if (addr && addr->IsValid ())
{ {
if (addr->IsIdentHash ()) if (addr->IsIdentHash ())
{ {
auto leaseSet = session->GetLocalDestination ()->FindLeaseSet(addr->identHash); auto leaseSet = session->GetLocalDestination ()->FindLeaseSet(addr->identHash);
if (leaseSet) if (leaseSet)
Connect(leaseSet, session); Connect(leaseSet, session);
@ -527,7 +527,7 @@ namespace client
std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete, std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete,
shared_from_this(), std::placeholders::_1)); shared_from_this(), std::placeholders::_1));
} }
} }
else // B33 else // B33
session->GetLocalDestination ()->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, session->GetLocalDestination ()->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey,
std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete, std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete,
@ -548,12 +548,12 @@ namespace client
m_SocketType = eSAMSocketTypeStream; m_SocketType = eSAMSocketTypeStream;
m_Stream = session->GetLocalDestination ()->CreateStream (remote); m_Stream = session->GetLocalDestination ()->CreateStream (remote);
if (m_Stream) if (m_Stream)
{ {
m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send
m_BufferOffset = 0; m_BufferOffset = 0;
I2PReceive (); I2PReceive ();
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
} }
else else
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
} }
@ -579,7 +579,7 @@ namespace client
{ {
SendI2PError ("Socket already in use"); SendI2PError ("Socket already in use");
return; return;
} }
std::map<std::string, std::string> params; std::map<std::string, std::string> params;
ExtractParams (buf, params); ExtractParams (buf, params);
std::string& id = params[SAM_PARAM_ID]; std::string& id = params[SAM_PARAM_ID];
@ -612,42 +612,42 @@ namespace client
{ {
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
return; return;
} }
if (session->GetLocalDestination ()->IsAcceptingStreams ()) if (session->GetLocalDestination ()->IsAcceptingStreams ())
{ {
SendI2PError ("Already accepting"); SendI2PError ("Already accepting");
return; return;
} }
auto it = params.find (SAM_PARAM_PORT); auto it = params.find (SAM_PARAM_PORT);
if (it == params.end ()) if (it == params.end ())
{ {
SendI2PError ("PORT is missing"); SendI2PError ("PORT is missing");
return; return;
} }
auto port = std::stoi (it->second); auto port = std::stoi (it->second);
if (port <= 0 || port >= 0xFFFF) if (port <= 0 || port >= 0xFFFF)
{ {
SendI2PError ("Invalid PORT"); SendI2PError ("Invalid PORT");
return; return;
} }
boost::system::error_code ec; boost::system::error_code ec;
auto ep = m_Socket.remote_endpoint (ec); auto ep = m_Socket.remote_endpoint (ec);
if (ec) if (ec)
{ {
SendI2PError ("Socket error"); SendI2PError ("Socket error");
return; return;
} }
ep.port (port); ep.port (port);
m_SocketType = eSAMSocketTypeForward; m_SocketType = eSAMSocketTypeForward;
m_ID = id; m_ID = id;
m_IsAccepting = true; m_IsAccepting = true;
std::string& silent = params[SAM_PARAM_SILENT]; std::string& silent = params[SAM_PARAM_SILENT];
if (silent == SAM_VALUE_TRUE) m_IsSilent = true; if (silent == SAM_VALUE_TRUE) m_IsSilent = true;
session->GetLocalDestination ()->AcceptStreams (std::bind (&SAMSocket::HandleI2PForward, session->GetLocalDestination ()->AcceptStreams (std::bind (&SAMSocket::HandleI2PForward,
shared_from_this (), std::placeholders::_1, ep)); shared_from_this (), std::placeholders::_1, ep));
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
} }
size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data) size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data)
{ {
LogPrint (eLogDebug, "SAM: Datagram send: ", buf, " ", len); LogPrint (eLogDebug, "SAM: Datagram send: ", buf, " ", len);
@ -778,8 +778,8 @@ namespace client
// session exists // session exists
SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), false); SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), false);
return; return;
} }
std::string& style = params[SAM_PARAM_STYLE]; std::string& style = params[SAM_PARAM_STYLE];
SAMSessionType type = eSAMSessionTypeUnknown; SAMSessionType type = eSAMSessionTypeUnknown;
if (style == SAM_VALUE_STREAM) type = eSAMSessionTypeStream; if (style == SAM_VALUE_STREAM) type = eSAMSessionTypeStream;
// TODO: implement other styles // TODO: implement other styles
@ -800,14 +800,14 @@ namespace client
{ {
masterSession->subsessions.insert (id); masterSession->subsessions.insert (id);
SendSessionCreateReplyOk (); SendSessionCreateReplyOk ();
} }
else else
SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), false); SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), false);
} }
else else
SendI2PError ("Wrong session type"); SendI2PError ("Wrong session type");
} }
void SAMSocket::ProcessSessionRemove (char * buf, size_t len) void SAMSocket::ProcessSessionRemove (char * buf, size_t len)
{ {
auto session = m_Owner.FindSession(m_ID); auto session = m_Owner.FindSession(m_ID);
@ -819,17 +819,17 @@ namespace client
ExtractParams (buf, params); ExtractParams (buf, params);
std::string& id = params[SAM_PARAM_ID]; std::string& id = params[SAM_PARAM_ID];
if (!masterSession->subsessions.erase (id)) if (!masterSession->subsessions.erase (id))
{ {
SendMessageReply (SAM_SESSION_STATUS_INVALID_KEY, strlen(SAM_SESSION_STATUS_INVALID_KEY), false); SendMessageReply (SAM_SESSION_STATUS_INVALID_KEY, strlen(SAM_SESSION_STATUS_INVALID_KEY), false);
return; return;
} }
m_Owner.CloseSession (id); m_Owner.CloseSession (id);
SendSessionCreateReplyOk (); SendSessionCreateReplyOk ();
} }
else else
SendI2PError ("Wrong session type"); SendI2PError ("Wrong session type");
} }
void SAMSocket::SendI2PError(const std::string & msg) void SAMSocket::SendI2PError(const std::string & msg)
{ {
LogPrint (eLogError, "SAM: I2P error: ", msg); LogPrint (eLogError, "SAM: I2P error: ", msg);
@ -1067,7 +1067,7 @@ namespace client
LogPrint (eLogWarning, "SAM: I2P acceptor has been reset"); LogPrint (eLogWarning, "SAM: I2P acceptor has been reset");
} }
void SAMSocket::HandleI2PForward (std::shared_ptr<i2p::stream::Stream> stream, void SAMSocket::HandleI2PForward (std::shared_ptr<i2p::stream::Stream> stream,
boost::asio::ip::tcp::endpoint ep) boost::asio::ip::tcp::endpoint ep)
{ {
if (stream) if (stream)
@ -1076,7 +1076,7 @@ namespace client
auto newSocket = std::make_shared<SAMSocket>(m_Owner); auto newSocket = std::make_shared<SAMSocket>(m_Owner);
newSocket->SetSocketType (eSAMSocketTypeStream); newSocket->SetSocketType (eSAMSocketTypeStream);
auto s = shared_from_this (); auto s = shared_from_this ();
newSocket->GetSocket ().async_connect (ep, newSocket->GetSocket ().async_connect (ep,
[s, newSocket, stream](const boost::system::error_code& ecode) [s, newSocket, stream](const boost::system::error_code& ecode)
{ {
if (!ecode) if (!ecode)
@ -1098,12 +1098,12 @@ namespace client
} }
else else
stream->AsyncClose (); stream->AsyncClose ();
}); });
} }
else else
LogPrint (eLogWarning, "SAM: I2P forward acceptor has been reset"); LogPrint (eLogWarning, "SAM: I2P forward acceptor has been reset");
} }
void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
{ {
LogPrint (eLogDebug, "SAM: Datagram received ", len); LogPrint (eLogDebug, "SAM: Datagram received ", len);
@ -1198,11 +1198,11 @@ namespace client
localDestination (dest) localDestination (dest)
{ {
} }
SAMSingleSession::~SAMSingleSession () SAMSingleSession::~SAMSingleSession ()
{ {
i2p::client::context.DeleteLocalDestination (localDestination); i2p::client::context.DeleteLocalDestination (localDestination);
} }
void SAMSingleSession::StopLocalDestination () void SAMSingleSession::StopLocalDestination ()
{ {
@ -1220,24 +1220,24 @@ namespace client
for (const auto& it: subsessions) for (const auto& it: subsessions)
m_Bridge.CloseSession (it); m_Bridge.CloseSession (it);
subsessions.clear (); subsessions.clear ();
} }
SAMSubSession::SAMSubSession (std::shared_ptr<SAMMasterSession> master, const std::string& name, SAMSessionType type, int port): SAMSubSession::SAMSubSession (std::shared_ptr<SAMMasterSession> master, const std::string& name, SAMSessionType type, int port):
SAMSession (master->m_Bridge, name, type), masterSession (master), inPort (port) SAMSession (master->m_Bridge, name, type), masterSession (master), inPort (port)
{ {
if (Type == eSAMSessionTypeStream) if (Type == eSAMSessionTypeStream)
{ {
auto d = masterSession->GetLocalDestination ()->CreateStreamingDestination (inPort); auto d = masterSession->GetLocalDestination ()->CreateStreamingDestination (inPort);
if (d) d->Start (); if (d) d->Start ();
} }
// TODO: implement datagrams // TODO: implement datagrams
} }
std::shared_ptr<ClientDestination> SAMSubSession::GetLocalDestination () std::shared_ptr<ClientDestination> SAMSubSession::GetLocalDestination ()
{ {
return masterSession ? masterSession->GetLocalDestination () : nullptr; return masterSession ? masterSession->GetLocalDestination () : nullptr;
} }
void SAMSubSession::StopLocalDestination () void SAMSubSession::StopLocalDestination ()
{ {
auto dest = GetLocalDestination (); auto dest = GetLocalDestination ();
@ -1245,10 +1245,10 @@ namespace client
{ {
auto d = dest->RemoveStreamingDestination (inPort); auto d = dest->RemoveStreamingDestination (inPort);
if (d) d->Stop (); if (d) d->Stop ();
} }
// TODO: implement datagrams // TODO: implement datagrams
} }
SAMBridge::SAMBridge (const std::string& address, int port, bool singleThread): SAMBridge::SAMBridge (const std::string& address, int port, bool singleThread):
RunnableService ("SAM"), m_IsSingleThread (singleThread), RunnableService ("SAM"), m_IsSingleThread (singleThread),
m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)), m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)),
@ -1311,8 +1311,8 @@ namespace client
{ {
std::unique_lock<std::mutex> lock(m_OpenSocketsMutex); std::unique_lock<std::mutex> lock(m_OpenSocketsMutex);
m_OpenSockets.push_back(socket); m_OpenSockets.push_back(socket);
} }
void SAMBridge::RemoveSocket(const std::shared_ptr<SAMSocket> & socket) void SAMBridge::RemoveSocket(const std::shared_ptr<SAMSocket> & socket)
{ {
std::unique_lock<std::mutex> lock(m_OpenSocketsMutex); std::unique_lock<std::mutex> lock(m_OpenSocketsMutex);
@ -1403,7 +1403,7 @@ namespace client
auto ret = m_Sessions.emplace (session->Name, session); auto ret = m_Sessions.emplace (session->Name, session);
return ret.second; return ret.second;
} }
void SAMBridge::CloseSession (const std::string& id) void SAMBridge::CloseSession (const std::string& id)
{ {
std::shared_ptr<SAMSession> session; std::shared_ptr<SAMSession> session;

View File

@ -80,7 +80,7 @@ namespace client
const char SAM_VALUE_STREAM[] = "STREAM"; const char SAM_VALUE_STREAM[] = "STREAM";
const char SAM_VALUE_DATAGRAM[] = "DATAGRAM"; const char SAM_VALUE_DATAGRAM[] = "DATAGRAM";
const char SAM_VALUE_RAW[] = "RAW"; const char SAM_VALUE_RAW[] = "RAW";
const char SAM_VALUE_MASTER[] = "MASTER"; const char SAM_VALUE_MASTER[] = "MASTER";
const char SAM_VALUE_TRUE[] = "true"; const char SAM_VALUE_TRUE[] = "true";
const char SAM_VALUE_FALSE[] = "false"; const char SAM_VALUE_FALSE[] = "false";
@ -188,14 +188,14 @@ namespace client
std::string Name; std::string Name;
SAMSessionType Type; SAMSessionType Type;
std::shared_ptr<boost::asio::ip::udp::endpoint> UDPEndpoint; // TODO: move std::shared_ptr<boost::asio::ip::udp::endpoint> UDPEndpoint; // TODO: move
SAMSession (SAMBridge & parent, const std::string & name, SAMSessionType type); SAMSession (SAMBridge & parent, const std::string & name, SAMSessionType type);
virtual ~SAMSession () {}; virtual ~SAMSession () {};
virtual std::shared_ptr<ClientDestination> GetLocalDestination () = 0; virtual std::shared_ptr<ClientDestination> GetLocalDestination () = 0;
virtual void StopLocalDestination () = 0; virtual void StopLocalDestination () = 0;
virtual void Close () { CloseStreams (); }; virtual void Close () { CloseStreams (); };
void CloseStreams (); void CloseStreams ();
}; };
@ -208,15 +208,15 @@ namespace client
std::shared_ptr<ClientDestination> GetLocalDestination () { return localDestination; }; std::shared_ptr<ClientDestination> GetLocalDestination () { return localDestination; };
void StopLocalDestination (); void StopLocalDestination ();
}; };
struct SAMMasterSession: public SAMSingleSession struct SAMMasterSession: public SAMSingleSession
{ {
std::set<std::string> subsessions; std::set<std::string> subsessions;
SAMMasterSession (SAMBridge & parent, const std::string & name, std::shared_ptr<ClientDestination> dest): SAMMasterSession (SAMBridge & parent, const std::string & name, std::shared_ptr<ClientDestination> dest):
SAMSingleSession (parent, name, eSAMSessionTypeMaster, dest) {}; SAMSingleSession (parent, name, eSAMSessionTypeMaster, dest) {};
void Close (); void Close ();
}; };
struct SAMSubSession: public SAMSession struct SAMSubSession: public SAMSession
{ {
@ -227,8 +227,8 @@ namespace client
// implements SAMSession // implements SAMSession
std::shared_ptr<ClientDestination> GetLocalDestination (); std::shared_ptr<ClientDestination> GetLocalDestination ();
void StopLocalDestination (); void StopLocalDestination ();
}; };
class SAMBridge: private i2p::util::RunnableService class SAMBridge: private i2p::util::RunnableService
{ {
public: public: