mirror of
https://github.com/PurpleI2P/i2pd
synced 2024-11-09 15:50:26 +03:00
clean line trailing spaces and tabs
Signed-off-by: R4SAS <r4sas@i2pmail.org>
This commit is contained in:
parent
94661f697b
commit
edc0162163
@ -395,8 +395,8 @@ namespace client
|
||||
auto it1 = m_RouterInfoHandlers.find (it->first);
|
||||
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, ¶ms),
|
||||
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…
Reference in New Issue
Block a user