mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 21:37:17 +01:00
Merge pull request #5 from orignal/master
Merge pull request #5 from orignal/master
This commit is contained in:
commit
877be9c68e
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@ CC = g++
|
|||
CFLAGS = -g -Wall -std=c++0x
|
||||
OBJECTS = i2p.o base64.o NTCPSession.o RouterInfo.o Transports.o RouterContext.o \
|
||||
NetDb.o LeaseSet.o Tunnel.o TunnelEndpoint.o TunnelGateway.o TransitTunnel.o \
|
||||
I2NPProtocol.o Log.o Garlic.o HTTPServer.o Streaming.o Identity.o
|
||||
I2NPProtocol.o Log.o Garlic.o HTTPServer.o Streaming.o Identity.o SSU.o
|
||||
INCFLAGS =
|
||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem
|
||||
LIBS =
|
||||
|
|
93
NetDb.cpp
93
NetDb.cpp
|
@ -1,6 +1,7 @@
|
|||
#include "I2PEndian.h"
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <cryptopp/gzip.h>
|
||||
#include "base64.h"
|
||||
|
@ -206,6 +207,8 @@ namespace data
|
|||
};
|
||||
|
||||
int count = 0, deletedCount = 0;
|
||||
auto total = m_RouterInfos.size ();
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
for (auto it: m_RouterInfos)
|
||||
{
|
||||
if (it.second->IsUpdated ())
|
||||
|
@ -215,7 +218,16 @@ namespace data
|
|||
it.second->SetUpdated (false);
|
||||
count++;
|
||||
}
|
||||
else if (it.second->IsUnreachable ())
|
||||
else
|
||||
{
|
||||
// RouterInfo expires in 72 hours if more than 300
|
||||
if (total > 300 && ts > it.second->GetTimestamp () + 3*24*3600*1000LL) // 3 days
|
||||
{
|
||||
total--;
|
||||
it.second->SetUnreachable (true);
|
||||
}
|
||||
|
||||
if (it.second->IsUnreachable ())
|
||||
{
|
||||
if (boost::filesystem::exists (GetFilePath (directory, it.second)))
|
||||
{
|
||||
|
@ -224,6 +236,7 @@ namespace data
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count > 0)
|
||||
LogPrint (count," new/updated routers saved");
|
||||
if (deletedCount > 0)
|
||||
|
@ -239,16 +252,6 @@ namespace data
|
|||
|
||||
void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet)
|
||||
{
|
||||
auto floodfill= GetRandomNTCPRouter (true);
|
||||
if (floodfill)
|
||||
RequestDestination (destination, floodfill, isLeaseSet);
|
||||
else
|
||||
LogPrint ("No floodfill routers found");
|
||||
}
|
||||
|
||||
void NetDb::RequestDestination (const IdentHash& destination, const RouterInfo * floodfill, bool isLeaseSet)
|
||||
{
|
||||
if (!floodfill) return;
|
||||
i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel ();
|
||||
if (outbound)
|
||||
{
|
||||
|
@ -256,9 +259,31 @@ namespace data
|
|||
if (inbound)
|
||||
{
|
||||
RequestedDestination * dest = CreateRequestedDestination (destination, isLeaseSet);
|
||||
auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
|
||||
if (floodfill)
|
||||
{
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
// our RouterInfo
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeRouter,
|
||||
floodfill->GetIdentHash (), 0,
|
||||
CreateDatabaseStoreMsg ()
|
||||
});
|
||||
|
||||
// DatabaseLookup message
|
||||
dest->SetLastOutboundTunnel (outbound);
|
||||
auto msg = dest->CreateRequestMessage (floodfill, inbound);
|
||||
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg);
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeRouter,
|
||||
floodfill->GetIdentHash (), 0,
|
||||
dest->CreateRequestMessage (floodfill, inbound)
|
||||
});
|
||||
|
||||
outbound->SendTunnelDataMsg (msgs);
|
||||
}
|
||||
else
|
||||
LogPrint ("No more floodfills found");
|
||||
}
|
||||
else
|
||||
LogPrint ("No inbound tunnels found");
|
||||
|
@ -487,7 +512,8 @@ namespace data
|
|||
if (msg) m_Queue.Put (msg);
|
||||
}
|
||||
|
||||
const RouterInfo * NetDb::GetClosestFloodfill (const IdentHash& destination) const
|
||||
const RouterInfo * NetDb::GetClosestFloodfill (const IdentHash& destination,
|
||||
const std::set<IdentHash>& excluded) const
|
||||
{
|
||||
RouterInfo * r = nullptr;
|
||||
XORMetric minMetric;
|
||||
|
@ -495,7 +521,7 @@ namespace data
|
|||
minMetric.SetMax ();
|
||||
for (auto it: m_RouterInfos)
|
||||
{
|
||||
if (it.second->IsFloodfill () &&! it.second->IsUnreachable ())
|
||||
if (it.second->IsFloodfill () &&! it.second->IsUnreachable () && !excluded.count (it.first))
|
||||
{
|
||||
XORMetric m = destKey ^ it.second->GetRoutingKey ();
|
||||
if (m < minMetric)
|
||||
|
@ -507,5 +533,42 @@ namespace data
|
|||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void NetDb::DownloadRouterInfo (const std::string& address, const std::string& filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::asio::ip::tcp::iostream site(address, "http");
|
||||
if (!site)
|
||||
{
|
||||
//site.expires_from_now (boost::posix_time::seconds (10)); // wait for 10 seconds
|
||||
site << "GET " << filename << "HTTP/1.0\nHost: " << address << "\nAccept: */*\nConnection: close\n\n";
|
||||
// read response
|
||||
std::string version, statusMessage;
|
||||
site >> version; // HTTP version
|
||||
int status;
|
||||
site >> status; // status
|
||||
std::getline (site, statusMessage);
|
||||
if (status == 200) // OK
|
||||
{
|
||||
std::string header;
|
||||
while (header != "\n")
|
||||
std::getline (site, header);
|
||||
// read content
|
||||
std::stringstream ss;
|
||||
ss << site.rdbuf();
|
||||
AddRouterInfo ((uint8_t *)ss.str ().c_str (), ss.str ().size ());
|
||||
}
|
||||
else
|
||||
LogPrint ("HTTP response ", status);
|
||||
}
|
||||
else
|
||||
LogPrint ("Can't connect to ", address);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint ("Failed to download ", filename, " : ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
5
NetDb.h
5
NetDb.h
|
@ -26,6 +26,7 @@ namespace data
|
|||
|
||||
const IdentHash& GetDestination () const { return m_Destination; };
|
||||
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
|
||||
const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; };
|
||||
const RouterInfo * GetLastRouter () const { return m_LastRouter; };
|
||||
const i2p::tunnel::InboundTunnel * GetLastReplyTunnel () const { return m_LastReplyTunnel; };
|
||||
bool IsExploratory () const { return m_IsExploratory; };
|
||||
|
@ -62,7 +63,6 @@ namespace data
|
|||
|
||||
void RequestDestination (const char * b32); // in base32
|
||||
void RequestDestination (const IdentHash& destination, bool isLeaseSet = false);
|
||||
void RequestDestination (const IdentHash& destination, const RouterInfo * floodfill, bool isLeaseSet = false);
|
||||
|
||||
void HandleDatabaseStoreMsg (uint8_t * buf, size_t len);
|
||||
void HandleDatabaseSearchReplyMsg (I2NPMessage * msg);
|
||||
|
@ -76,9 +76,10 @@ namespace data
|
|||
|
||||
void Load (const char * directory);
|
||||
void SaveUpdated (const char * directory);
|
||||
void DownloadRouterInfo (const std::string& address, const std::string& filename); // for reseed
|
||||
void Run (); // exploratory thread
|
||||
void Explore ();
|
||||
const RouterInfo * GetClosestFloodfill (const IdentHash& destination) const;
|
||||
const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||
|
||||
RequestedDestination * CreateRequestedDestination (const IdentHash& dest,
|
||||
bool isLeaseSet, bool isExploratory = false);
|
||||
|
|
|
@ -128,7 +128,13 @@ namespace data
|
|||
size = be16toh (size);
|
||||
while (r < size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
char key[500], value[500];
|
||||
// TODO: investigate why properties get read as one long string under Windows
|
||||
// length should not be more than 44
|
||||
#else
|
||||
char key[50], value[50];
|
||||
#endif
|
||||
r += ReadString (key, s);
|
||||
s.seekg (1, std::ios_base::cur); r++; // =
|
||||
r += ReadString (value, s);
|
||||
|
|
44
SSU.cpp
Normal file
44
SSU.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include <boost/bind.hpp>
|
||||
#include "Log.h"
|
||||
#include "hmac.h"
|
||||
#include "SSU.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace ssu
|
||||
{
|
||||
SSUServer::SSUServer (boost::asio::io_service& service, int port):
|
||||
m_Socket (service, boost::asio::ip::udp::v4 (), port)
|
||||
{
|
||||
}
|
||||
|
||||
void SSUServer::Start ()
|
||||
{
|
||||
Receive ();
|
||||
}
|
||||
|
||||
void SSUServer::Stop ()
|
||||
{
|
||||
m_Socket.close ();
|
||||
}
|
||||
|
||||
void SSUServer::Receive ()
|
||||
{
|
||||
m_Socket.async_receive_from (boost::asio::buffer (m_ReceiveBuffer, SSU_MTU), m_SenderEndpoint,
|
||||
boost::bind (&SSUServer::HandleReceivedFrom, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
if (!ecode)
|
||||
{
|
||||
LogPrint ("SSU received ", bytes_transferred, " bytes");
|
||||
// Handle
|
||||
Receive ();
|
||||
}
|
||||
else
|
||||
LogPrint ("SSU receive error: ", ecode.message ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
36
SSU.h
Normal file
36
SSU.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef SSU_H__
|
||||
#define SSU_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace ssu
|
||||
{
|
||||
const int SSU_MTU = 1484;
|
||||
|
||||
class SSUServer
|
||||
{
|
||||
public:
|
||||
|
||||
SSUServer (boost::asio::io_service& service, int port);
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
private:
|
||||
|
||||
void Receive ();
|
||||
void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::ip::udp::socket m_Socket;
|
||||
boost::asio::ip::udp::endpoint m_SenderEndpoint;
|
||||
uint8_t m_ReceiveBuffer[SSU_MTU];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -12,7 +12,7 @@ namespace i2p
|
|||
Transports transports;
|
||||
|
||||
Transports::Transports ():
|
||||
m_Thread (0), m_Work (m_Service),m_NTCPAcceptor (0)
|
||||
m_Thread (nullptr), m_Work (m_Service),m_NTCPAcceptor (nullptr), m_SSUServer (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,11 +34,22 @@ namespace i2p
|
|||
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service,
|
||||
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port));
|
||||
|
||||
LogPrint ("Start listening port ", address.port);
|
||||
LogPrint ("Start listening TCP port ", address.port);
|
||||
auto conn = new i2p::ntcp::NTCPServerConnection (m_Service);
|
||||
m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this,
|
||||
conn, boost::asio::placeholders::error));
|
||||
}
|
||||
else if (address.transportStyle == RouterInfo::eTransportSSU)
|
||||
{
|
||||
if (!m_SSUServer)
|
||||
{
|
||||
m_SSUServer = new i2p::ssu::SSUServer (m_Service, address.port);
|
||||
LogPrint ("Start listening UDP port ", address.port);
|
||||
m_SSUServer->Start ();
|
||||
}
|
||||
else
|
||||
LogPrint ("SSU server already exists");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +60,12 @@ namespace i2p
|
|||
m_NTCPSessions.clear ();
|
||||
delete m_NTCPAcceptor;
|
||||
|
||||
if (m_SSUServer)
|
||||
{
|
||||
m_SSUServer->Stop ();
|
||||
delete m_SSUServer;
|
||||
}
|
||||
|
||||
m_IsRunning = false;
|
||||
m_Service.stop ();
|
||||
if (m_Thread)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
#include <boost/asio.hpp>
|
||||
#include "NTCPSession.h"
|
||||
#include "SSU.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "I2NPProtocol.h"
|
||||
|
||||
|
@ -47,6 +48,7 @@ namespace i2p
|
|||
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor;
|
||||
|
||||
std::map<i2p::data::IdentHash, i2p::ntcp::NTCPSession *> m_NTCPSessions;
|
||||
i2p::ssu::SSUServer * m_SSUServer;
|
||||
|
||||
public:
|
||||
|
||||
|
|
60
hmac.h
Normal file
60
hmac.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#ifndef HMAC_H__
|
||||
#define HMAC_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
|
||||
#include <cryptopp/md5.h>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
const uint64_t IPAD = 0x3636363636363636;
|
||||
const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
|
||||
|
||||
inline void HMACMD5Digest (uint8_t * msg, size_t len, uint8_t * key, uint8_t * digest)
|
||||
// key is 32 bytes
|
||||
// digest is 16 bytes
|
||||
// block size is 64 bytes
|
||||
{
|
||||
size_t totalLen = len + 64 + 32;
|
||||
uint8_t * buf = new uint8_t[totalLen]; // TODO: reuse buffers
|
||||
// ikeypad
|
||||
((uint64_t *)buf)[0] = ((uint64_t *)key)[0] ^ IPAD;
|
||||
((uint64_t *)buf)[1] = ((uint64_t *)key)[1] ^ IPAD;
|
||||
((uint64_t *)buf)[2] = ((uint64_t *)key)[2] ^ IPAD;
|
||||
((uint64_t *)buf)[3] = ((uint64_t *)key)[3] ^ IPAD;
|
||||
((uint64_t *)buf)[4] = IPAD;
|
||||
((uint64_t *)buf)[5] = IPAD;
|
||||
((uint64_t *)buf)[6] = IPAD;
|
||||
((uint64_t *)buf)[7] = IPAD;
|
||||
// concatenate with msg
|
||||
memcpy (buf + 64, msg, len);
|
||||
// calculate first hash
|
||||
uint8_t hash[16]; // MD5
|
||||
CryptoPP::Weak1::MD5().CalculateDigest (hash, buf, len + 64);
|
||||
|
||||
// okeypad
|
||||
((uint64_t *)buf)[0] = ((uint64_t *)key)[0] ^ OPAD;
|
||||
((uint64_t *)buf)[1] = ((uint64_t *)key)[1] ^ OPAD;
|
||||
((uint64_t *)buf)[2] = ((uint64_t *)key)[2] ^ OPAD;
|
||||
((uint64_t *)buf)[3] = ((uint64_t *)key)[3] ^ OPAD;
|
||||
((uint64_t *)buf)[4] = OPAD;
|
||||
((uint64_t *)buf)[5] = OPAD;
|
||||
((uint64_t *)buf)[6] = OPAD;
|
||||
((uint64_t *)buf)[7] = OPAD;
|
||||
// copy first hash after okeypad
|
||||
memcpy (buf + 64, hash, 16);
|
||||
// fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
|
||||
memset (buf + 72, 0, 16);
|
||||
|
||||
// calculate digest
|
||||
CryptoPP::Weak1::MD5().CalculateDigest (digest, buf, totalLen);
|
||||
delete[] buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in a new issue