Browse Source

Merge pull request #5 from orignal/master

Merge pull request #5 from orignal/master
pull/13/head
chertov 11 years ago
parent
commit
877be9c68e
  1. 2
      Makefile
  2. 103
      NetDb.cpp
  3. 9
      NetDb.h
  4. 6
      RouterInfo.cpp
  5. 44
      SSU.cpp
  6. 36
      SSU.h
  7. 21
      Transports.cpp
  8. 2
      Transports.h
  9. 60
      hmac.h

2
Makefile

@ -3,7 +3,7 @@ CC = g++
CFLAGS = -g -Wall -std=c++0x CFLAGS = -g -Wall -std=c++0x
OBJECTS = i2p.o base64.o NTCPSession.o RouterInfo.o Transports.o RouterContext.o \ 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 \ 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 = INCFLAGS =
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem
LIBS = LIBS =

103
NetDb.cpp

@ -1,6 +1,7 @@
#include "I2PEndian.h" #include "I2PEndian.h"
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include <boost/asio.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <cryptopp/gzip.h> #include <cryptopp/gzip.h>
#include "base64.h" #include "base64.h"
@ -206,6 +207,8 @@ namespace data
}; };
int count = 0, deletedCount = 0; int count = 0, deletedCount = 0;
auto total = m_RouterInfos.size ();
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it: m_RouterInfos) for (auto it: m_RouterInfos)
{ {
if (it.second->IsUpdated ()) if (it.second->IsUpdated ())
@ -215,13 +218,23 @@ namespace data
it.second->SetUpdated (false); it.second->SetUpdated (false);
count++; count++;
} }
else if (it.second->IsUnreachable ()) else
{ {
if (boost::filesystem::exists (GetFilePath (directory, it.second))) // RouterInfo expires in 72 hours if more than 300
{ if (total > 300 && ts > it.second->GetTimestamp () + 3*24*3600*1000LL) // 3 days
boost::filesystem::remove (GetFilePath (directory, it.second)); {
deletedCount++; total--;
it.second->SetUnreachable (true);
} }
if (it.second->IsUnreachable ())
{
if (boost::filesystem::exists (GetFilePath (directory, it.second)))
{
boost::filesystem::remove (GetFilePath (directory, it.second));
deletedCount++;
}
}
} }
} }
if (count > 0) if (count > 0)
@ -239,16 +252,6 @@ namespace data
void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet) 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 (); i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel ();
if (outbound) if (outbound)
{ {
@ -256,9 +259,31 @@ namespace data
if (inbound) if (inbound)
{ {
RequestedDestination * dest = CreateRequestedDestination (destination, isLeaseSet); RequestedDestination * dest = CreateRequestedDestination (destination, isLeaseSet);
dest->SetLastOutboundTunnel (outbound); auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
auto msg = dest->CreateRequestMessage (floodfill, inbound); if (floodfill)
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg); {
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);
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 else
LogPrint ("No inbound tunnels found"); LogPrint ("No inbound tunnels found");
@ -487,7 +512,8 @@ namespace data
if (msg) m_Queue.Put (msg); 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; RouterInfo * r = nullptr;
XORMetric minMetric; XORMetric minMetric;
@ -495,7 +521,7 @@ namespace data
minMetric.SetMax (); minMetric.SetMax ();
for (auto it: m_RouterInfos) 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 (); XORMetric m = destKey ^ it.second->GetRoutingKey ();
if (m < minMetric) if (m < minMetric)
@ -507,5 +533,42 @@ namespace data
} }
return r; 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 ());
}
}
} }
} }

9
NetDb.h

@ -26,7 +26,8 @@ namespace data
const IdentHash& GetDestination () const { return m_Destination; }; const IdentHash& GetDestination () const { return m_Destination; };
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); }; int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
const RouterInfo * GetLastRouter () const { return m_LastRouter; }; const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; };
const RouterInfo * GetLastRouter () const { return m_LastRouter; };
const i2p::tunnel::InboundTunnel * GetLastReplyTunnel () const { return m_LastReplyTunnel; }; const i2p::tunnel::InboundTunnel * GetLastReplyTunnel () const { return m_LastReplyTunnel; };
bool IsExploratory () const { return m_IsExploratory; }; bool IsExploratory () const { return m_IsExploratory; };
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); }; bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
@ -62,8 +63,7 @@ namespace data
void RequestDestination (const char * b32); // in base32 void RequestDestination (const char * b32); // in base32
void RequestDestination (const IdentHash& destination, bool isLeaseSet = false); 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 HandleDatabaseStoreMsg (uint8_t * buf, size_t len);
void HandleDatabaseSearchReplyMsg (I2NPMessage * msg); void HandleDatabaseSearchReplyMsg (I2NPMessage * msg);
@ -76,9 +76,10 @@ namespace data
void Load (const char * directory); void Load (const char * directory);
void SaveUpdated (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 Run (); // exploratory thread
void Explore (); 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, RequestedDestination * CreateRequestedDestination (const IdentHash& dest,
bool isLeaseSet, bool isExploratory = false); bool isLeaseSet, bool isExploratory = false);

6
RouterInfo.cpp

@ -128,7 +128,13 @@ namespace data
size = be16toh (size); size = be16toh (size);
while (r < size) while (r < size)
{ {
#ifdef _WIN32
char key[500], value[500]; 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); r += ReadString (key, s);
s.seekg (1, std::ios_base::cur); r++; // = s.seekg (1, std::ios_base::cur); r++; // =
r += ReadString (value, s); r += ReadString (value, s);

44
SSU.cpp

@ -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

@ -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

21
Transports.cpp

@ -12,7 +12,7 @@ namespace i2p
Transports transports; Transports transports;
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, m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service,
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port)); 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); auto conn = new i2p::ntcp::NTCPServerConnection (m_Service);
m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this, m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this,
conn, boost::asio::placeholders::error)); 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 (); m_NTCPSessions.clear ();
delete m_NTCPAcceptor; delete m_NTCPAcceptor;
if (m_SSUServer)
{
m_SSUServer->Stop ();
delete m_SSUServer;
}
m_IsRunning = false; m_IsRunning = false;
m_Service.stop (); m_Service.stop ();
if (m_Thread) if (m_Thread)

2
Transports.h

@ -7,6 +7,7 @@
#include <string> #include <string>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "NTCPSession.h" #include "NTCPSession.h"
#include "SSU.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
@ -47,6 +48,7 @@ namespace i2p
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor; boost::asio::ip::tcp::acceptor * m_NTCPAcceptor;
std::map<i2p::data::IdentHash, i2p::ntcp::NTCPSession *> m_NTCPSessions; std::map<i2p::data::IdentHash, i2p::ntcp::NTCPSession *> m_NTCPSessions;
i2p::ssu::SSUServer * m_SSUServer;
public: public:

60
hmac.h

@ -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…
Cancel
Save