clean line trailing spaces and tabs

Signed-off-by: R4SAS <r4sas@i2pmail.org>
pull/1717/head
R4SAS 3 years ago
parent 94661f697b
commit edc0162163
No known key found for this signature in database
GPG Key ID: 66F6C87B98EBCFE2

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

@ -225,7 +225,7 @@ namespace transport
}
std::string strType (GetProto (address)), strPort (std::to_string (address->port));
int err = UPNPCOMMAND_SUCCESS;
err = CheckMapping (strPort.c_str (), strType.c_str ());
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_SHA512_P521:
publicKeyLength = BlindECDSA (m_SigType, priv, seed, BlindEncodedPrivateKeyECDSA, blindedPriv, blindedPub);
break;
break;
case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
i2p::crypto::GetEd25519 ()->BlindPrivateKey (priv, seed, blindedPriv, blindedPub);
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
break;
case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
{
uint8_t exp[64];
i2p::crypto::Ed25519::ExpandPrivateKey (priv, exp);
uint8_t exp[64];
i2p::crypto::Ed25519::ExpandPrivateKey (priv, exp);
i2p::crypto::GetEd25519 ()->BlindPrivateKey (exp, seed, blindedPriv, blindedPub);
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
break;
}
}
default:
LogPrint (eLogError, "Blinding: Can't blind signature type ", (int)m_SigType);
}

@ -389,7 +389,7 @@ namespace crypto
{
size_t len = 32;
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
}
}
#else
memcpy (m_PrivateKey, priv, 32);
if (calculatePublic)
@ -440,7 +440,7 @@ namespace crypto
bn2buf (a, encrypted + 1, 256);
encrypted[257] = 0;
bn2buf (b, encrypted + 258, 256);
BN_free (a);
BN_CTX_end (ctx);
BN_CTX_free (ctx);
@ -1295,7 +1295,7 @@ namespace crypto
}
// Noise
void NoiseSymmetricState::MixHash (const uint8_t * buf, size_t len)
{
SHA256_CTX ctx;
@ -1311,7 +1311,7 @@ namespace crypto
// 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)
{
// pub is Bob's public static key, hh = SHA256(h)
@ -1321,19 +1321,19 @@ namespace crypto
SHA256_Update (&ctx, hh, 32);
SHA256_Update (&ctx, pub, 32);
SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub)
}
}
void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub)
{
static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars
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
}; // hh = SHA256(protocol_name || 0)
InitNoiseState (state, (const uint8_t *)protocolName, hh, pub); // ck = protocol_name || 0
}
}
void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub)
{
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,
0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e
}; // SHA256 (protocolNameHash)
InitNoiseState (state, protocolNameHash, hh, pub);
}
InitNoiseState (state, protocolNameHash, hh, 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,
0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c
}; // SHA256 (protocolNameHash)
InitNoiseState (state, protocolNameHash, hh, pub);
}
InitNoiseState (state, protocolNameHash, hh, pub);
}
// init and terminate
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;

@ -95,7 +95,7 @@ namespace crypto
bool IsElligatorIneligible () const { return m_IsElligatorIneligible; }
void SetElligatorIneligible () { m_IsElligatorIneligible = true; }
private:
uint8_t m_PublicKey[32];
@ -110,7 +110,7 @@ namespace crypto
};
// 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
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]*/;
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 InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2)
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets)
// init and terminate
void InitCrypto (bool precomputation, bool aesni, bool avx, bool force);
void TerminateCrypto ();

@ -29,7 +29,7 @@ namespace crypto
public:
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
};

@ -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;
for (auto& it: m_PendingRoutingSessions)
@ -384,7 +384,7 @@ namespace datagram
}
else
return nullptr;
auto leaseRouter = i2p::data::netdb.FindRouter (path->remoteLease->tunnelGateway);
path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(nullptr,
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 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
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 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 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; };

@ -89,7 +89,7 @@ namespace client
bool dontpublish = false;
i2p::config::GetOption (it->second, dontpublish);
m_IsPublic = !dontpublish;
}
}
it = params->find (I2CP_PARAM_LEASESET_TYPE);
if (it != params->end ())
m_LeaseSetType = std::stoi(it->second);
@ -367,8 +367,8 @@ namespace client
HandleDatabaseSearchReplyMessage (payload, len);
break;
case eI2NPShortTunnelBuildReply: // might come as garlic encrypted
i2p::HandleI2NPMessage (CreateI2NPMessage (typeID, payload, len, msgID));
break;
i2p::HandleI2NPMessage (CreateI2NPMessage (typeID, payload, len, msgID));
break;
default:
LogPrint (eLogWarning, "Destination: Unexpected I2NP message type ", typeID);
return false;
@ -395,7 +395,7 @@ namespace client
LogPrint (eLogDebug, "Destination: Remote LeaseSet");
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
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
{
leaseSet = it->second;
@ -487,7 +487,7 @@ namespace client
i2p::data::IdentHash peerHash (buf + 33 + i*32);
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
}
}
@ -767,11 +767,11 @@ namespace client
uint8_t replyKey[32], replyTag[32];
RAND_bytes (replyKey, 32); // random session key
RAND_bytes (replyTag, isECIES ? 8 : 32); // random session tag
if (isECIES)
if (isECIES)
AddECIESx25519Key (replyKey, replyTag);
else
else
AddSessionKey (replyKey, replyTag);
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
request->outboundTunnel->SendTunnelDataMsg (
{
@ -866,8 +866,8 @@ namespace client
ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
bool isPublic, const std::map<std::string, std::string> * params):
LeaseSetDestination (service, isPublic, params),
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
LeaseSetDestination (service, isPublic, params),
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS),
m_DatagramDestination (nullptr), m_RefCounter (0),
m_ReadyChecker(service)
@ -916,11 +916,11 @@ namespace client
encryptionKey->GenerateKeys ();
encryptionKey->CreateDecryptor ();
if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
{
{
m_ECIESx25519EncryptionKey.reset (encryptionKey);
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
m_StandardEncryptionKey.reset (encryptionKey);
}
@ -939,7 +939,7 @@ namespace client
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
if (it != params->end ())
i2p::config::GetOption (it->second, m_IsStreamingAnswerPings);
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
{
// authentication for encrypted LeaseSet
@ -1099,21 +1099,21 @@ namespace client
void ClientDestination::SendPing (const i2p::data::IdentHash& to)
{
if (m_StreamingDestination)
{
{
auto leaseSet = FindLeaseSet (to);
if (leaseSet)
m_StreamingDestination->SendPing (leaseSet);
else
{
{
auto s = m_StreamingDestination;
RequestDestination (to,
[s](std::shared_ptr<const i2p::data::LeaseSet> ls)
{
if (ls) s->SendPing (ls);
});
}
}
}
}
}
}
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)
{
if (ls) s->SendPing (ls);
});
}
});
}
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const
{
if (port)
@ -1182,18 +1182,18 @@ namespace client
auto ret = it->second;
m_StreamingDestinationsByPorts.erase (it);
return ret;
}
}
}
return nullptr;
}
}
i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination (bool gzip)
{
if (m_DatagramDestination == nullptr)
m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis (), gzip);
return m_DatagramDestination;
}
}
std::vector<std::shared_ptr<const i2p::stream::Stream> > ClientDestination::GetAllStreams () const
{
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_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_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
const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min";
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 int DEFAULT_INITIAL_ACK_DELAY = 200; // milliseconds
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;
@ -139,7 +139,7 @@ namespace client
void SetLeaseSetUpdated ();
bool IsPublic () const { return m_IsPublic; };
void SetPublic (bool pub) { m_IsPublic = pub; };
void SetPublic (bool pub) { m_IsPublic = pub; };
protected:
@ -251,7 +251,7 @@ namespace client
void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor);
int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; }
// datagram
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
i2p::datagram::DatagramDestination * CreateDatagramDestination (bool gzip = true);

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

@ -1,4 +1,3 @@
/*
* 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_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_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180
@ -46,7 +45,7 @@ namespace garlic
RatchetTagSet () {};
virtual ~RatchetTagSet () {};
void DHInitialize (const uint8_t * rootKey, const uint8_t * k);
void NextSessionTagRatchet ();
uint64_t GetNextSessionTag ();
@ -57,14 +56,14 @@ namespace garlic
int GetTagSetID () const { return m_TagSetID; };
void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; };
private:
i2p::data::Tag<64> m_SessionTagKeyData;
uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64], m_NextRootKey[32];
int m_NextIndex, m_NextSymmKeyIndex;
std::unordered_map<int, i2p::data::Tag<32> > m_ItermediateSymmKeys;
int m_TagSetID = 0;
};
@ -74,27 +73,27 @@ namespace garlic
{
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) {};
bool IsNS () const { return m_IsNS; };
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; };
void Expire ();
bool IsExpired (uint64_t ts) const;
bool IsExpired (uint64_t ts) const;
virtual bool IsIndexExpired (int index) const;
virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index);
private:
int m_TrimBehindIndex = 0;
std::shared_ptr<ECIESX25519AEADRatchetSession> m_Session;
bool m_IsNS;
uint64_t m_ExpirationTimestamp = 0;
};
};
class SymmetricKeyTagSet: public ReceiveRatchetTagSet
{
@ -104,13 +103,13 @@ namespace garlic
bool IsIndexExpired (int index) const { return false; };
bool HandleNextMessage (uint8_t * buf, size_t len, int index);
private:
GarlicDestination * m_Destination;
uint8_t m_Key[32];
};
};
enum ECIESx25519BlockType
{
eECIESx25519BlkDateTime = 0,
@ -128,7 +127,7 @@ namespace garlic
const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02;
const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04;
class ECIESX25519AEADRatchetSession: public GarlicRoutingSession,
class ECIESX25519AEADRatchetSession: public GarlicRoutingSession,
private i2p::crypto::NoiseSymmetricState,
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);
std::shared_ptr<I2NPMessage> WrapSingleMessage (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; }
void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); }
void Terminate () { m_IsTerminated = true; }
void SetDestination (const i2p::data::IdentHash& dest) // TODO:
{
@ -171,19 +170,19 @@ namespace garlic
bool CheckExpired (uint64_t ts); // true is expired
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 IsRatchets () const { return true; };
bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; };
bool IsTerminated () const { return m_IsTerminated; }
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
protected:
protected:
i2p::crypto::NoiseSymmetricState& GetNoiseState () { return *this; };
void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; };
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);
private:
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 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);
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 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;
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
uint8_t m_PaddingSizes[32], m_NextPaddingSize;
public:
// for HTTP only
@ -240,12 +239,12 @@ namespace garlic
RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState);
bool HandleNextMessage (const uint8_t * buf, size_t len);
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
private:
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> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey);
}

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

@ -115,7 +115,7 @@ namespace garlic
virtual bool MessageConfirmed (uint32_t msgID);
virtual bool IsRatchets () const { return false; };
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
void SetLeaseSetUpdated ()
@ -251,7 +251,7 @@ namespace garlic
void RemoveECIESx25519Session (const uint8_t * staticKey);
void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len);
uint8_t * GetPayloadBuffer ();
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
virtual void SetLeaseSetUpdated ();

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

@ -167,8 +167,8 @@ namespace http
*/
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
} // i2p

@ -170,8 +170,8 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
const uint8_t * replyTag, bool replyECIES)
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
const uint8_t * replyTag, bool replyECIES)
{
int cnt = excludedFloodfills.size ();
auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage ();
@ -243,8 +243,8 @@ namespace i2p
return m;
}
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router,
uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router,
uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
{
if (!router) // we send own RouterInfo
router = context.GetSharedRouterInfo ();
@ -398,7 +398,7 @@ namespace i2p
retCode = 30; // always reject with bandwidth reason (30)
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
i2p::crypto::CBCEncryption encryption;
for (int j = 0; j < num; j++)
@ -409,7 +409,7 @@ namespace i2p
uint8_t nonce[12];
memset (nonce, 0, 12);
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
{
LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed");
@ -547,7 +547,7 @@ namespace i2p
{
LogPrint (eLogDebug, "I2NP: Short request record ", i, " is ours");
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);
return;
@ -558,10 +558,10 @@ namespace i2p
return;
}
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);
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);
bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG;
if (isEndpoint)
@ -602,8 +602,8 @@ namespace i2p
if (j == i)
{
memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode;
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16,
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode;
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
{
LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed");
@ -611,7 +611,7 @@ namespace i2p
}
}
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;
}
// send reply
@ -620,10 +620,10 @@ namespace i2p
auto replyMsg = NewI2NPShortMessage ();
replyMsg->Concat (buf, len);
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?
{
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;
memcpy (&tag, noiseState.m_CK, 8);
// we send it to reply tunnel

@ -56,7 +56,7 @@ namespace i2p
// TunnelBuild
const size_t TUNNEL_BUILD_RECORD_SIZE = 528;
const size_t SHORT_TUNNEL_BUILD_RECORD_SIZE = 218;
// BuildRequestRecordEncrypted
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;
@ -98,7 +98,7 @@ namespace i2p
// ShortResponseRecord
const size_t SHORT_RESPONSE_RECORD_OPTIONS_OFFSET = 0;
const size_t SHORT_RESPONSE_RECORD_RET_OFFSET = 201;
enum I2NPMessageType
{
eI2NPDummyMsg = 0,
@ -273,8 +273,8 @@ namespace tunnel
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);
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
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);

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

@ -84,9 +84,9 @@ namespace data
typedef uint16_t SigningKeyType;
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
{
{
public:
IdentityEx ();
@ -138,7 +138,7 @@ namespace data
mutable i2p::crypto::Verifier * m_Verifier = nullptr;
mutable std::mutex m_VerifierMutex;
size_t m_ExtendedLen;
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
};
class PrivateKeys // for eepsites

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

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

@ -42,7 +42,7 @@ namespace transport
const int NTCP2_CLOCK_SKEW = 60; // in seconds
const int NTCP2_MAX_OUTGOING_QUEUE_SIZE = 500; // how many messages we can queue up
enum NTCP2BlockType
{
eNTCP2BlkDateTime = 0,
@ -118,7 +118,7 @@ namespace transport
i2p::data::IdentHash m_RemoteIdentHash;
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;
size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen;
@ -137,7 +137,7 @@ namespace transport
void Done ();
void Close () { m_Socket.close (); }; // for accept
void DeleteNextReceiveBuffer (uint64_t ts);
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
const boost::asio::ip::tcp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
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
uint16_t m_PaddingSizes[16];
int m_NextPaddingSize;
int m_NextPaddingSize;
};
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 SetLocalAddress (const boost::asio::ip::address& localAddress);
private:
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 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);
// timer
void ScheduleTermination ();
void HandleTerminationTimer (const boost::system::error_code& ecode);
@ -285,7 +285,7 @@ namespace transport
boost::asio::ip::tcp::resolver m_Resolver;
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress;
public:
// for HTTP/I2PControl

@ -56,9 +56,9 @@ namespace data
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
{
{
Reseed ();
}
}
else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false))
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 ());
if (i2p::context.IsFloodfill ())
m_Floodfills.push_back (i2p::context.GetSharedRouterInfo ());
i2p::config::GetOption("persist.profiles", m_PersistProfiles);
m_IsRunning = true;
@ -148,7 +148,7 @@ namespace data
}
if (!m_IsRunning) break;
if (!i2p::transport::transports.IsOnline ()) continue; // don't manage netdb when offline
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts - lastManageRequest >= 15) // manage requests every 15 seconds
{
@ -170,8 +170,8 @@ namespace data
lastDestinationCleanup = ts;
}
// publish
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
// publish
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
{
bool publish = false;
if (m_PublishReplyToken)
@ -179,15 +179,15 @@ namespace data
// next publishing attempt
if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true;
}
else if (i2p::context.GetLastUpdateTime () > lastPublish ||
ts - lastPublish >= NETDB_PUBLISH_INTERVAL)
{
else if (i2p::context.GetLastUpdateTime () > lastPublish ||
ts - lastPublish >= NETDB_PUBLISH_INTERVAL)
{
// new publish
m_PublishExcluded.clear ();
if (i2p::context.IsFloodfill ())
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // do publish to ourselves
publish = true;
}
}
if (publish) // update timestamp and publish
{
i2p::context.UpdateTimestamp (ts);
@ -290,7 +290,7 @@ namespace data
if (inserted)
{
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);
m_Floodfills.push_back (r);
@ -476,14 +476,14 @@ namespace data
{
auto r = std::make_shared<RouterInfo>(path);
if (r->GetRouterIdentity () && !r->IsUnreachable () && r->HasValidAddresses ())
{
{
r->DeleteBuffer ();
r->ClearProperties (); // properties are not used for regular routers
if (m_RouterInfos.emplace (r->GetIdentHash (), r).second)
{
{
if (r->IsFloodfill () && r->IsEligibleFloodfill ())
m_Floodfills.push_back (r);
}
}
}
else
{
@ -591,7 +591,7 @@ namespace data
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;
auto own = i2p::context.GetSharedRouterInfo ();
auto own = i2p::context.GetSharedRouterInfo ();
for (auto& it: m_RouterInfos)
{
if (it.second == own) continue; // skip own
@ -608,8 +608,8 @@ namespace data
}
// make router reachable back if too few routers or floodfills
if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS ||
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
it.second->SetUnreachable (false);
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
it.second->SetUnreachable (false);
// find & mark expired routers
if (!it.second->IsReachable () && it.second->IsSSU (false))
{
@ -626,7 +626,7 @@ namespace data
// delete RI file
m_Storage.Remove(ident);
deletedCount++;
if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false;
if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false;
}
} // m_RouterInfos iteration
@ -674,7 +674,7 @@ namespace data
if (floodfill)
{
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
if (direct)
transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
@ -688,10 +688,10 @@ namespace data
else
{
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found");
m_Requests.RequestComplete (destination, nullptr);
}
}
}
m_Requests.RequestComplete (destination, nullptr);
}
}
}
else
{
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no floodfills found");
@ -1051,8 +1051,8 @@ namespace data
m_PublishExcluded.clear ();
m_PublishReplyToken = 0;
}
}
}
void NetDb::Explore (int numDestinations)
{
// 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");
m_PublishExcluded.clear ();
}
auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
if (floodfill)
{
@ -1122,19 +1122,19 @@ namespace data
m_PublishExcluded.insert (floodfill->GetIdentHash ());
m_PublishReplyToken = replyToken;
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
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
else
{
// otherwise through exploratory
// otherwise through exploratory
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
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)
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0,
CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
}
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0,
CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
}
}
}
@ -1174,7 +1174,7 @@ namespace data
{
return !router->IsHidden () && router != compatibleWith &&
(reverse ? compatibleWith->IsReachableFrom (*router) :
router->IsReachableFrom (*compatibleWith)) &&
router->IsReachableFrom (*compatibleWith)) &&
router->IsECIES ();
});
}
@ -1184,7 +1184,7 @@ namespace data
return GetRandomRouter (
[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 ());
});
}
@ -1216,7 +1216,7 @@ namespace data
return !router->IsHidden () && router != compatibleWith &&
(reverse ? compatibleWith->IsReachableFrom (*router) :
router->IsReachableFrom (*compatibleWith)) &&
(router->GetCaps () & RouterInfo::eHighBandwidth) &&
(router->GetCaps () & RouterInfo::eHighBandwidth) &&
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
router->IsECIES ();
});
@ -1238,12 +1238,12 @@ namespace data
return it->second;
// try some routers around
auto it1 = m_RouterInfos.begin ();
if (inds[0])
if (inds[0])
{
// before
inds[1] %= inds[0];
inds[1] %= inds[0];
std::advance (it1, (inds[1] + inds[0])/2);
}
}
else
it1 = it;
auto it2 = it;
@ -1254,7 +1254,7 @@ namespace data
std::advance (it2, inds[2]);
}
// it1 - from, it2 - to
it = it1;
it = it1;
while (it != it2 && it != m_RouterInfos.end ())
{
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_PUBLISH_INTERVAL = 60 * 40;
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_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

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

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

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

@ -67,7 +67,7 @@ namespace garlic
void Init ();
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 ()
{
return std::shared_ptr<i2p::data::RouterInfo> (&m_RouterInfo,
@ -97,7 +97,7 @@ namespace garlic
void SetNetID (int netID) { m_NetID = netID; };
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data);
bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data);
void UpdatePort (int port); // called from 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);
@ -160,7 +160,7 @@ namespace garlic
void SaveKeys ();
bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize);
private:
i2p::data::RouterInfo m_RouterInfo;

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

@ -52,7 +52,7 @@ namespace data
const uint8_t COST_NTCP2_NON_PUBLISHED = 14;
const uint8_t COST_SSU_DIRECT = 9;
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
class RouterInfo: public RoutingDestination
{
@ -68,7 +68,7 @@ namespace data
eAllTransports = 0xFF
};
typedef uint8_t CompatibleTransports;
enum Caps
{
eFloodfill = 0x01,
@ -86,7 +86,7 @@ namespace data
eSSUTesting = 0x04,
eSSUIntroducer = 0x08
};
enum TransportStyle
{
eTransportUnknown = 0,
@ -150,7 +150,7 @@ namespace data
bool IsPublishedNTCP2 () const { return IsNTCP2 () && published; };
bool IsReachableSSU () const { return (bool)ssu && (published || !ssu->introducers.empty ()); };
bool UsesIntroducer () const { return (bool)ssu && !ssu->introducers.empty (); };
bool IsIntroducer () const { return caps & eSSUIntroducer; };
bool IsPeerTesting () const { return caps & eSSUTesting; };
@ -173,14 +173,14 @@ namespace data
int GetVersion () const { return m_Version; };
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> GetPublishedNTCP2V4Address () const;
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
std::shared_ptr<const Address> GetSSUV6Address () const;
std::shared_ptr<const Address> GetYggdrasilAddress () const;
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);
bool AddIntroducer (const Introducer& introducer);
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
@ -196,28 +196,28 @@ namespace data
bool IsSSU (bool v4only = true) const;
bool IsSSUV6 () const;
bool IsNTCP2 (bool v4only = true) const;
bool IsNTCP2V6 () const;
bool IsNTCP2V6 () const;
bool IsV6 () const;
bool IsV4 () const;
bool IsMesh () const;
bool IsMesh () const;
void EnableV6 ();
void DisableV6 ();
void EnableV4 ();
void DisableV4 ();
void EnableMesh ();
void DisableMesh ();
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
bool IsReachableFrom (const RouterInfo& other) const { return m_ReachableTransports & other.m_SupportedTransports; };
void DisableMesh ();
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 IsReachableBy (CompatibleTransports transports) const { return m_ReachableTransports & transports; };
CompatibleTransports GetCompatibleTransports (bool incoming) const { return incoming ? m_ReachableTransports : m_SupportedTransports; };
bool HasValidAddresses () const { return m_SupportedTransports; };
CompatibleTransports GetCompatibleTransports (bool incoming) const { return incoming ? m_ReachableTransports : m_SupportedTransports; };
bool HasValidAddresses () const { return m_SupportedTransports; };
bool IsHidden () const { return m_Caps & eHidden; };
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
bool IsEligibleFloodfill () const;
bool IsPeerTesting (bool v4) const;
bool IsIntroducer (bool v4) const;
bool IsPeerTesting (bool v4) const;
bool IsIntroducer (bool v4) const;
uint8_t GetCaps () const { return m_Caps; };
void SetCaps (uint8_t caps);
void SetCaps (const char * caps);

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

@ -67,17 +67,17 @@ namespace transport
i2p::util::MemoryPool<Fragment>& GetFragmentsPool () { return m_FragmentsPool; };
i2p::util::MemoryPool<IncompleteMessage>& GetIncompleteMessagesPool () { return m_IncompleteMessagesPool; };
i2p::util::MemoryPool<SentMessage>& GetSentMessagesPool () { return m_SentMessagesPool; };
uint16_t GetPort () const { return m_Endpoint.port (); };
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 AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay);
void RemoveRelay (uint32_t tag);
std::shared_ptr<SSUSession> FindRelaySession (uint32_t tag);
void RescheduleIntroducersUpdateTimer ();
void RescheduleIntroducersUpdateTimerV6 ();
void NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session = nullptr);
PeerTestParticipant GetPeerTestParticipant (uint32_t nonce);
std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce);
@ -98,7 +98,7 @@ namespace transport
void HandleReceivedPackets (std::vector<SSUPacket *> packets,
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);
template<typename 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::ip::udp::endpoint m_Endpoint, m_EndpointV6;
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;
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;
@ -145,7 +145,7 @@ namespace transport
i2p::util::MemoryPool<IncompleteMessage> m_IncompleteMessagesPool;
i2p::util::MemoryPool<SentMessage> m_SentMessagesPool;
i2p::util::MemoryPoolMt<SSUPacket> m_PacketsPool;
public:
// for HTTP only
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };

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

@ -79,7 +79,7 @@ namespace transport
uint64_t receivedFragmentsBits;
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) {};
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
};
@ -102,7 +102,7 @@ namespace transport
void Start ();
void Stop ();
void CleanUp (uint64_t ts);
void ProcessMessage (uint8_t * buf, size_t len);
void FlushReceivedMessage ();
void Send (std::shared_ptr<i2p::I2NPMessage> msg);

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

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

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

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

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

@ -112,10 +112,10 @@ namespace stream
memcpy (buf, b, len);
}
SendBuffer (size_t l): // create empty buffer
len(l), offset (0)
len(l), offset (0)
{
buf = new uint8_t[len];
}
}
~SendBuffer ()
{
delete[] buf;
@ -180,7 +180,7 @@ namespace stream
size_t Send (const uint8_t * buf, size_t len);
void AsyncSend (const uint8_t * buf, size_t len, SendHandler handler);
void SendPing ();
template<typename Buffer, typename ReceiveHandler>
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
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>(
std::chrono::system_clock::now().time_since_epoch()).count ();
}
static uint32_t GetLocalHoursSinceEpoch ()
{
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::endpoint ep;
while (it != end)
{
{
ep = *it;
if (!ep.address ().is_unspecified ())
{
if (ep.address ().is_v4 ())
{
if (i2p::context.SupportsV4 ()) found = true;
{
if (i2p::context.SupportsV4 ()) found = true;
}
else if (ep.address ().is_v6 ())
{
if (i2p::util::net::IsYggdrasilAddress (ep.address ()))
{
if (i2p::context.SupportsMesh ()) found = true;
}
}
else if (i2p::context.SupportsV6 ()) found = true;
}
}
}
if (found) break;
it++;
}
@ -94,8 +94,8 @@ namespace util
{
LogPrint (eLogError, "Timestamp: can't find compatible address for ", address);
return;
}
}
boost::asio::ip::udp::socket socket (service);
socket.open (ep.protocol (), ec);
if (!ec)
@ -220,13 +220,13 @@ namespace util
uint64_t GetSecondsSinceEpoch ()
{
return GetLocalSecondsSinceEpoch () + g_TimeOffset;
}
}
uint32_t GetMinutesSinceEpoch ()
{
return GetLocalMinutesSinceEpoch () + g_TimeOffset/60;
}
uint32_t GetHoursSinceEpoch ()
{
return GetLocalHoursSinceEpoch () + g_TimeOffset/3600;

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

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

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

@ -40,10 +40,10 @@ namespace tunnel
const int STANDARD_NUM_RECORDS = 4; // in VariableTunnelBuild message
const int MAX_NUM_RECORDS = 8;
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_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
{
eTunnelStatePending,
@ -106,7 +106,7 @@ namespace tunnel
bool LatencyIsKnown() const { return m_Latency > 0; }
bool IsSlow () const { return LatencyIsKnown() && (int)m_Latency > HIGH_LATENCY_PER_HOP*GetNumHops (); }
protected:
void PrintHops (std::stringstream& s) const;
@ -119,7 +119,7 @@ namespace tunnel
std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null
TunnelState m_State;
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
};
@ -225,11 +225,11 @@ namespace tunnel
void StopTunnelPool (std::shared_ptr<TunnelPool> pool);
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint);
private:
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);
template<class TTunnel>
@ -266,7 +266,7 @@ namespace tunnel
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_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool;
// some stats
int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations;

@ -81,34 +81,34 @@ namespace tunnel
decryption.SetKey (replyKey);
decryption.SetIV (replyIV);
decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record);
}
}
void ECIESTunnelHopConfig::EncryptECIES (const uint8_t * plainText, size_t len, uint8_t * encrypted)
{
if (!ident) return;
i2p::crypto::InitNoiseNState (*this, ident->GetEncryptionPublicKey ());
auto ephemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
memcpy (encrypted, ephemeralKeys->GetPublicKey (), 32);
memcpy (encrypted, ephemeralKeys->GetPublicKey (), 32);
MixHash (encrypted, 32); // h = SHA256(h || sepk)
encrypted += 32;
uint8_t sharedSecret[32];
ephemeralKeys->Agree (ident->GetEncryptionPublicKey (), sharedSecret); // x25519(sesk, hepk)
MixKey (sharedSecret);
MixKey (sharedSecret);
uint8_t nonce[12];
memset (nonce, 0, 12);
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");
return;
}
}
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
{
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)
{
// generate keys
@ -119,7 +119,7 @@ namespace tunnel
// fill clear text
uint8_t flag = 0;
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];
htobe32buf (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID);
htobe32buf (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID);
@ -149,16 +149,16 @@ namespace tunnel
{
LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed");
return false;
}
}
return true;
}
}
void ShortECIESTunnelHopConfig::CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID)
{
// fill clear text
uint8_t flag = 0;
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 ];
htobe32buf (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID);
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;
EncryptECIES (clearText, SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE, record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET);
// 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);
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);
if (isEndpoint)
{
i2p::crypto::HKDF (m_CK, nullptr, 0, "TunnelLayerIVKey", m_CK);
memcpy (ivKey, m_CK + 32, 32);
i2p::crypto::HKDF (m_CK, nullptr, 0, "TunnelLayerIVKey", m_CK);
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
}
else
memcpy (ivKey, m_CK, 32); // last HKDF
memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16);
}
bool ShortECIESTunnelHopConfig::DecryptBuildResponseRecord (uint8_t * records) const
{
uint8_t * record = records + recordIndex*SHORT_TUNNEL_BUILD_RECORD_SIZE;
@ -199,9 +199,9 @@ namespace tunnel
{
LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed");
return false;
}
}
return true;
}
}
void ShortECIESTunnelHopConfig::DecryptRecord (uint8_t * records, int index) const
{
@ -210,7 +210,7 @@ namespace tunnel
memset (nonce, 0, 12);
nonce[4] = index; // nonce is index
i2p::crypto::ChaCha20 (record, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, record);
}
}
uint64_t ShortECIESTunnelHopConfig::GetGarlicKey (uint8_t * key) const
{
@ -218,7 +218,7 @@ namespace tunnel
memcpy (&tag, m_CK, 8);
memcpy (key, m_CK + 32, 32);
return tag;
}
}
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");
}
if (hop)
{
{
if (prev)
prev->SetNext (hop);
else
m_FirstHop = hop;
prev = hop;
}
}
}
m_LastHop = prev;
}

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

@ -57,7 +57,7 @@ namespace tunnel
// first fragment
if (m_CurrentMsgID)
AddIncompleteCurrentMessage (); // we have got a new message while previous is not complete
m_CurrentMessage.deliveryType = (TunnelDeliveryType)((flag >> 5) & 0x03);
switch (m_CurrentMessage.deliveryType)
{
@ -108,8 +108,8 @@ namespace tunnel
{
HandleFollowOnFragment (msgID, isLastFragment, fragmentNum, fragment, size); // another
m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
}
}
}
}
else
{
// new message
@ -131,27 +131,27 @@ namespace tunnel
}
else
m_CurrentMessage.data = msg;
if (isLastFragment)
{
{
// single message
HandleNextMessage (m_CurrentMessage);
m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
}
}
else if (msgID)
{
// first fragment of a new message
m_CurrentMessage.nextFragmentNum = 1;
m_CurrentMessage.receiveTime = i2p::util::GetMillisecondsSinceEpoch ();
HandleOutOfSequenceFragments (msgID, m_CurrentMessage);
}
}
else
{
{
LogPrint (eLogError, "TunnelMessage: Message is fragmented, but msgID is not presented");
m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
}
}
}
}
fragment += size;
}
}
@ -159,7 +159,7 @@ namespace tunnel
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)
{
auto it = m_IncompleteMessages.find (msgID);
@ -213,15 +213,15 @@ namespace tunnel
msg.data = newMsg;
}
if (msg.data->Concat (fragment, size) < size) // concatenate fragment
{
{
LogPrint (eLogError, "TunnelMessage: I2NP buffer overflow ", msg.data->maxLen);
return false;
}
}
}
else
return false;
return true;
}
}
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");
m_CurrentMsgID = 0; m_CurrentMessage.data = nullptr;
}
}
}
void TunnelEndpoint::AddIncompleteCurrentMessage ()
{
@ -255,13 +255,13 @@ namespace tunnel
LogPrint (eLogError, "TunnelMessage: Incomplete message ", m_CurrentMsgID, " already exists");
m_CurrentMessage.data = nullptr;
m_CurrentMsgID = 0;
}
}
}
}
void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum,
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);
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);
@ -276,10 +276,10 @@ namespace tunnel
HandleNextMessage (msg);
if (&msg == &m_CurrentMessage)
{
m_CurrentMsgID = 0;
m_CurrentMsgID = 0;
m_CurrentMessage.data = nullptr;
}
else
}
else
m_IncompleteMessages.erase (msgID);
LogPrint (eLogDebug, "TunnelMessage: All fragments of message ", msgID, " found");
break;

@ -49,14 +49,14 @@ namespace tunnel
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
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 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
void HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg);
void AddIncompleteCurrentMessage ();
private:
std::unordered_map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages;

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

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

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

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

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

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

@ -660,7 +660,7 @@ namespace client
else
SendReplyError ("Local LeaseSet Not found");
}
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: clear");
@ -786,7 +786,7 @@ namespace client
m_CommandHandlers[BOB_COMMAND_INPORT] = &BOBCommandSession::InportCommandHandler;
m_CommandHandlers[BOB_COMMAND_QUIET] = &BOBCommandSession::QuietCommandHandler;
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_LIST] = &BOBCommandSession::ListCommandHandler;
m_CommandHandlers[BOB_COMMAND_OPTION] = &BOBCommandSession::OptionCommandHandler;

@ -406,7 +406,7 @@ namespace client
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_OUTBOUND_TUNNELS_QUANTITY, "3" },
@ -720,10 +720,10 @@ namespace client
std::shared_ptr<ClientDestination> localDestination = nullptr;
auto it = destinations.find (keys);
if (it != destinations.end ())
{
{
localDestination = it->second;
localDestination->SetPublic (true);
}
}
else
{
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());
}
else
{
{
ins.first->second->isUpdated = true;
LogPrint(eLogError, "Clients: I2P Server Forward for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash()), "/", port, " already exists");
}
}
continue;
}

@ -107,7 +107,7 @@ namespace client
// i18n
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; };
private:
void ReadTunnels ();
@ -157,7 +157,7 @@ namespace client
// i18n
std::shared_ptr<const i2p::i18n::Locale> m_Language;
public:
// for HTTP

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

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

@ -49,7 +49,7 @@ namespace client
void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
void Connect (bool isUniqueLocal = true);
void Connect (const boost::asio::ip::address& localAddress);
protected:
void Terminate ();
@ -59,7 +59,7 @@ namespace client
virtual void Write (const uint8_t * buf, size_t len); // can be overloaded
void HandleWrite (const boost::system::error_code& ecode);
virtual void WriteToStream (const uint8_t * buf, size_t len); // can be overloaded
void StreamReceive ();
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleConnect (const boost::system::error_code& ecode);
@ -105,7 +105,7 @@ namespace client
protected:
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:
@ -154,11 +154,11 @@ namespace client
const char* GetName() { return m_Name.c_str (); }
void SetKeepAliveInterval (uint32_t keepAliveInterval);
private:
std::shared_ptr<const Address> GetAddress ();
void ScheduleKeepAliveTimer ();
void HandleKeepAliveTimer (const boost::system::error_code& ecode);
@ -174,8 +174,8 @@ namespace client
/** 2 minute timeout for udp sessions */
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 */
const size_t I2P_UDP_MAX_MTU = 64*1024;
@ -330,7 +330,7 @@ namespace client
bool IsUniqueLocal () const { return m_IsUniqueLocal; }
void SetLocalAddress (const std::string& localAddress);
const std::string& GetAddress() const { return m_Address; }
int GetPort () const { return m_Port; };
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)
{
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)))
return false;
// more here for outbound tunnels
@ -86,14 +86,14 @@ namespace client
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases();
// pick lease
std::shared_ptr<i2p::data::RouterInfo> obep;
while(!obep && leases.size() > 0)
while(!obep && leases.size() > 0)
{
auto idx = rand() % leases.size();
auto lease = leases[idx];
obep = i2p::data::netdb.FindRouter(lease->tunnelGateway);
leases.erase(leases.begin()+idx);
}
if(obep)
if(obep)
{
path.Add (obep);
LogPrint(eLogDebug, "Destination: Found OBEP matching IBGW");

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

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

Loading…
Cancel
Save