Beispiel #1
0
	void TunnelPool::CreateInboundTunnel ()
	{
		OutboundTunnel * outboundTunnel = m_OutboundTunnels.size () > 0 ? 
			*m_OutboundTunnels.begin () : tunnels.GetNextOutboundTunnel ();
		LogPrint ("Creating destination inbound tunnel...");
		const i2p::data::RouterInfo * prevHop = &i2p::context.GetRouterInfo ();	
		std::vector<const i2p::data::RouterInfo *> hops;
		int numHops = m_NumHops;
		if (outboundTunnel)
		{	
			// last hop
			auto hop = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router;
			if (hop->GetIdentHash () != i2p::context.GetIdentHash ()) // outbound shouldn't be zero-hop tunnel
			{	
				prevHop = hop;
				hops.push_back (prevHop);
				numHops--;
			}
		}
		for (int i = 0; i < numHops; i++)
		{
			auto hop = i2p::data::netdb.GetRandomRouter (prevHop);
			prevHop = hop;
			hops.push_back (hop);
		}		
		std::reverse (hops.begin (), hops.end ());	
		auto * tunnel = tunnels.CreateTunnel<InboundTunnel> (new TunnelConfig (hops));
		tunnel->SetTunnelPool (this);
	}
Beispiel #2
0
 void RouterContext::UpdateNTCPV6Address (const boost::asio::ip::address& host)
 {
     bool updated = false, found = false;    
     int port = 0;
     auto& addresses = m_RouterInfo.GetAddresses ();
     for (auto& addr : addresses)
     {
         if (addr.host.is_v6 () && addr.transportStyle == i2p::data::RouterInfo::eTransportNTCP)
         {
             if (addr.host != host)
             {
                 addr.host = host;
                 updated = true;
             }
             found = true;   
         }   
         else
             port = addr.port;   
     }   
     if (!found)
     {
         // create new address
         m_RouterInfo.AddNTCPAddress (host.to_string ().c_str (), port);
         auto mtu = i2p::util::net::GetMTU (host);
         if (mtu)
         {   
             LogPrint ("Our v6 MTU=", mtu);
             if (mtu > 1472) mtu = 1472; 
         }   
         m_RouterInfo.AddSSUAddress (host.to_string ().c_str (), port, GetIdentHash (), mtu ? mtu : 1472); // TODO
         updated = true;
     }
     if (updated)
         UpdateRouterInfo ();
 }
Beispiel #3
0
	void GarlicDestination::CleanupExpiredTags ()
	{
		// incoming
		uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
		int numExpiredTags = 0;
		for (auto it = m_Tags.begin (); it != m_Tags.end ();)
		{
			if (ts > it->first.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
			{
				numExpiredTags++;
				it = m_Tags.erase (it);
			}	
			else
				it++;
		}
		if (numExpiredTags > 0)
			LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ());

		// outgoing
		std::unique_lock<std::mutex> l(m_SessionsMutex);
		for (auto it = m_Sessions.begin (); it != m_Sessions.end ();)
		{
			it->second->GetSharedRoutingPath (); // delete shared path if necessary
			if (!it->second->CleanupExpiredTags ())
			{
				LogPrint (eLogInfo, "Routing session to ", it->first.ToBase32 (), " deleted");
				it = m_Sessions.erase (it);
			}
			else
				it++;
		}
	}
Beispiel #4
0
 bool AddressBook::GetAddress (const std::string& address, i2p::data::IdentityEx& identity)
 {
     if (!m_Storage) 
         m_Storage = CreateStorage ();
     i2p::data::IdentHash ident;
     if (!GetIdentHash (address, ident)) return false;
     return m_Storage->GetAddress (ident, identity);
 }   
Beispiel #5
0
void NetDbRequests::ManageRequests() {
  uint64_t ts = i2p::util::GetSecondsSinceEpoch();
  std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
  for (auto it = m_RequestedDestinations.begin();
      it != m_RequestedDestinations.end();) {
    auto& dest = it->second;
    bool done = false;
    // request is worthless after 1 minute
    if (ts < dest->GetCreationTime() + 60) {
      // no response for 5 seconds
      if (ts > dest->GetCreationTime() + 5)  {
        auto count = dest->GetExcludedPeers().size();
        std::size_t attempts(7);
        if (!dest->IsExploratory() && count < attempts) {
          auto pool = i2p::tunnel::tunnels.GetExploratoryPool();
          auto outbound = pool->GetNextOutboundTunnel();
          auto inbound = pool->GetNextInboundTunnel();
          auto nextFloodfill = netdb.GetClosestFloodfill(
              dest->GetDestination(),
              dest->GetExcludedPeers());
          if (nextFloodfill && outbound && inbound) {
            outbound->SendTunnelDataMsg(
                nextFloodfill->GetIdentHash(),
                0,
                dest->CreateRequestMessage(
                  nextFloodfill,
                  inbound));
          } else {
            done = true;
            if (!inbound)
              LogPrint(eLogWarn, "NetDbRequests: no inbound tunnels");
            if (!outbound)
              LogPrint(eLogWarn, "NetDbRequests: no outbound tunnels");
            if (!nextFloodfill)
              LogPrint(eLogWarn, "NetDbRequests: no more floodfills");
          }
        } else {
          if (!dest->IsExploratory())
            LogPrint(eLogWarn,
                "NetDbRequests: ", dest->GetDestination().ToBase64(),
                " not found after ", attempts, " attempts");
          done = true;
        }
      }
    } else {  // delete obsolete request
      done = true;
    }
    if (done)
      it = m_RequestedDestinations.erase(it);
    else
      it++;
  }
}
Beispiel #6
0
	void GarlicDestination::SaveTags ()
	{
		if (m_Tags.empty ()) return;
		std::string ident = GetIdentHash().ToBase32();
		std::string path  = i2p::fs::DataDirPath("tags", (ident + ".tags"));
		std::ofstream f (path, std::ofstream::binary | std::ofstream::out | std::ofstream::trunc);
		uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
		// 4 bytes timestamp, 32 bytes tag, 32 bytes key
		for (auto it: m_Tags)
		{
			if (ts < it.first.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
			{
				f.write ((char *)&it.first.creationTime, 4);
				f.write ((char *)it.first.data (), 32);
				f.write ((char *)it.second->GetKey ().data (), 32);
			}
		}
	}
Beispiel #7
0
	void TunnelPool::CreateInboundTunnel ()
	{
		OutboundTunnel * outboundTunnel = m_OutboundTunnels.size () > 0 ? 
			*m_OutboundTunnels.begin () : tunnels.GetNextOutboundTunnel ();
		LogPrint ("Creating destination inbound tunnel...");
		auto firstHop = i2p::data::netdb.GetRandomRouter (outboundTunnel ? outboundTunnel->GetEndpointRouter () : nullptr); 
		auto secondHop = outboundTunnel ? outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router : nullptr;
		if (!secondHop || secondHop->GetIdentHash () == i2p::context.GetIdentHash ())
			secondHop = i2p::data::netdb.GetRandomRouter (firstHop);	
		auto * tunnel = tunnels.CreateTunnel<InboundTunnel> (
			new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
				{                
			        firstHop, 
					secondHop
	            }),                 
			outboundTunnel);
		tunnel->SetTunnelPool (this);
	}
Beispiel #8
0
	void GarlicDestination::LoadTags ()
	{
		std::string ident = GetIdentHash().ToBase32();
		std::string path  = i2p::fs::DataDirPath("tags", (ident + ".tags"));
		uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
		if (ts < i2p::fs::GetLastUpdateTime (path) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
		{
			// might contain non-expired tags
			std::ifstream f (path, std::ifstream::binary);
			if (f)
			{
				std::map<i2p::crypto::AESKey, std::shared_ptr<AESDecryption> > keys;
				// 4 bytes timestamp, 32 bytes tag, 32 bytes key
				while (!f.eof ())
				{
					uint32_t t;
					uint8_t tag[32], key[32];
					f.read ((char *)&t, 4); if (f.eof ()) break;
					if (ts < t + INCOMING_TAGS_EXPIRATION_TIMEOUT)
					{
						f.read ((char *)tag, 32);
						f.read ((char *)key, 32);
					}
					else
						f.seekg (64, std::ios::cur); // skip
					if (f.eof ()) break;

					std::shared_ptr<AESDecryption> decryption;
					auto it = keys.find (key);
					if (it != keys.end ())
						decryption = it->second;
					else
						decryption = std::make_shared<AESDecryption>(key);
					m_Tags.insert (std::make_pair (SessionTag (tag, ts), decryption));
				}
				if (!m_Tags.empty ())
					LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident);
			}
		}
		i2p::fs::Remove (path);
	}
Beispiel #9
0
	void GarlicDestination::HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg)
	{
		uint8_t * buf = msg->GetPayload ();
		uint32_t length = bufbe32toh (buf);
		if (length > msg->GetLength ())
		{
			LogPrint (eLogError, "Garlic message length ", length, " exceeds I2NP message length ", msg->GetLength ());
			return;
		}	
		buf += 4; // length
		auto it = m_Tags.find (SessionTag(buf));
		if (it != m_Tags.end ())
		{
			// tag found. Use AES
			if (length >= 32)
			{	
				uint8_t iv[32]; // IV is first 16 bytes
				CryptoPP::SHA256().CalculateDigest(iv, buf, 32);
				it->second->SetIV (iv);
				it->second->Decrypt (buf + 32, length - 32, buf + 32);
				HandleAESBlock (buf + 32, length - 32, it->second, msg->from);
			}	
			else
				LogPrint (eLogError, "Garlic message length ", length, " is less than 32 bytes");
			m_Tags.erase (it); // tag might be used only once	
		}
		else
		{
			// tag not found. Use ElGamal
			ElGamalBlock elGamal;
			if (length >= 514 && i2p::crypto::ElGamalDecrypt (GetEncryptionPrivateKey (), buf, (uint8_t *)&elGamal, true))
			{	
				auto decryption = std::make_shared<i2p::crypto::CBCDecryption>();
				decryption->SetKey (elGamal.sessionKey);
				uint8_t iv[32]; // IV is first 16 bytes
				CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); 
				decryption->SetIV (iv);
				decryption->Decrypt(buf + 514, length - 514, buf + 514);
				HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
			}	
			else
				LogPrint (eLogError, "Failed to decrypt garlic");
		}

		// cleanup expired tags
		uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
		if (ts > m_LastTagsCleanupTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
		{
			if (m_LastTagsCleanupTime)
			{
				int numExpiredTags = 0;
				for (auto it = m_Tags.begin (); it != m_Tags.end ();)
				{
					if (ts > it->first.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
					{
						numExpiredTags++;
						it = m_Tags.erase (it);
					}	
					else
						it++;
				}
				LogPrint (numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ());
			}	
			m_LastTagsCleanupTime = ts;
		}	
	}