mirror of
https://github.com/PurpleI2P/i2pd
synced 2024-11-09 15:50:26 +03:00
clean line trailing spaces and tabs
Signed-off-by: R4SAS <r4sas@i2pmail.org>
This commit is contained in:
parent
94661f697b
commit
edc0162163
@ -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
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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 ();
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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; };
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 ();
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
@ -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
|
||||||
|
@ -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 "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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 ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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; };
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 ()
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
@ -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); };
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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, ¶ms),
|
LeaseSetDestination (service, isPublic, ¶ms),
|
||||||
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):
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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 (); };
|
||||||
|
@ -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");
|
||||||
|
@ -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;
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user