mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-04-23 17:36:37 +02:00
commit
45f91363ab
32 changed files with 1175 additions and 231 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -1,3 +1,10 @@
|
||||||
|
# i2pd
|
||||||
|
*.o
|
||||||
|
router.info
|
||||||
|
router.keys
|
||||||
|
i2p
|
||||||
|
netDb
|
||||||
|
|
||||||
#################
|
#################
|
||||||
## Eclipse
|
## Eclipse
|
||||||
#################
|
#################
|
||||||
|
|
|
@ -236,8 +236,8 @@ namespace garlic
|
||||||
auto it = m_Sessions.find (destination->GetIdentHash ());
|
auto it = m_Sessions.find (destination->GetIdentHash ());
|
||||||
if (it != m_Sessions.end ())
|
if (it != m_Sessions.end ())
|
||||||
{
|
{
|
||||||
m_Sessions.erase (it);
|
|
||||||
delete it->second;
|
delete it->second;
|
||||||
|
m_Sessions.erase (it);
|
||||||
}
|
}
|
||||||
GarlicRoutingSession * session = new GarlicRoutingSession (destination, 0); // not follow-on messages expected
|
GarlicRoutingSession * session = new GarlicRoutingSession (destination, 0); // not follow-on messages expected
|
||||||
m_Sessions[destination->GetIdentHash ()] = session;
|
m_Sessions[destination->GetIdentHash ()] = session;
|
||||||
|
|
|
@ -386,15 +386,13 @@ namespace i2p
|
||||||
TunnelGatewayHeader * header = (TunnelGatewayHeader *)msg->GetPayload ();
|
TunnelGatewayHeader * header = (TunnelGatewayHeader *)msg->GetPayload ();
|
||||||
uint32_t tunnelID = be32toh(header->tunnelID);
|
uint32_t tunnelID = be32toh(header->tunnelID);
|
||||||
uint16_t len = be16toh(header->length);
|
uint16_t len = be16toh(header->length);
|
||||||
LogPrint ("TunnelGateway of ", (int)len, " bytes for tunnel ", (unsigned int)tunnelID);
|
// we make payload as new I2NP message to send
|
||||||
|
msg->offset += sizeof (I2NPHeader) + sizeof (TunnelGatewayHeader);
|
||||||
|
msg->len = msg->offset + len;
|
||||||
|
LogPrint ("TunnelGateway of ", (int)len, " bytes for tunnel ", (unsigned int)tunnelID, ". Msg type ", (int)msg->GetHeader()->typeID);
|
||||||
i2p::tunnel::TransitTunnel * tunnel = i2p::tunnel::tunnels.GetTransitTunnel (tunnelID);
|
i2p::tunnel::TransitTunnel * tunnel = i2p::tunnel::tunnels.GetTransitTunnel (tunnelID);
|
||||||
if (tunnel)
|
if (tunnel)
|
||||||
{
|
|
||||||
// we make payload as new I2NP message to send
|
|
||||||
msg->offset += sizeof (I2NPHeader) + sizeof (TunnelGatewayHeader);
|
|
||||||
msg->len = msg->offset + len;
|
|
||||||
tunnel->SendTunnelDataMsg (nullptr, 0, msg);
|
tunnel->SendTunnelDataMsg (nullptr, 0, msg);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint ("Tunnel ", (unsigned int)tunnelID, " not found");
|
LogPrint ("Tunnel ", (unsigned int)tunnelID, " not found");
|
||||||
|
|
162
I2PEndian.cpp
162
I2PEndian.cpp
|
@ -1,81 +1,81 @@
|
||||||
#include "I2PEndian.h"
|
//#include "I2PEndian.h"
|
||||||
|
//
|
||||||
// http://habrahabr.ru/post/121811/
|
//// http://habrahabr.ru/post/121811/
|
||||||
// http://codepad.org/2ycmkz2y
|
//// http://codepad.org/2ycmkz2y
|
||||||
|
//
|
||||||
#include "LittleBigEndian.h"
|
//#include "LittleBigEndian.h"
|
||||||
|
//
|
||||||
uint16_t htobe16(uint16_t int16)
|
//uint16_t htobe16(uint16_t int16)
|
||||||
{
|
//{
|
||||||
BigEndian<uint16_t> u16(int16);
|
// BigEndian<uint16_t> u16(int16);
|
||||||
return u16.raw_value;
|
// return u16.raw_value;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
uint32_t htobe32(uint32_t int32)
|
//uint32_t htobe32(uint32_t int32)
|
||||||
{
|
//{
|
||||||
BigEndian<uint32_t> u32(int32);
|
// BigEndian<uint32_t> u32(int32);
|
||||||
return u32.raw_value;
|
// return u32.raw_value;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
uint64_t htobe64(uint64_t int64)
|
//uint64_t htobe64(uint64_t int64)
|
||||||
{
|
//{
|
||||||
BigEndian<uint64_t> u64(int64);
|
// BigEndian<uint64_t> u64(int64);
|
||||||
return u64.raw_value;
|
// return u64.raw_value;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
uint16_t be16toh(uint16_t big16)
|
//uint16_t be16toh(uint16_t big16)
|
||||||
{
|
//{
|
||||||
LittleEndian<uint16_t> u16(big16);
|
// LittleEndian<uint16_t> u16(big16);
|
||||||
return u16.raw_value;
|
// return u16.raw_value;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
uint32_t be32toh(uint32_t big32)
|
//uint32_t be32toh(uint32_t big32)
|
||||||
{
|
//{
|
||||||
LittleEndian<uint32_t> u32(big32);
|
// LittleEndian<uint32_t> u32(big32);
|
||||||
return u32.raw_value;
|
// return u32.raw_value;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
uint64_t be64toh(uint64_t big64)
|
//uint64_t be64toh(uint64_t big64)
|
||||||
{
|
//{
|
||||||
LittleEndian<uint64_t> u64(big64);
|
// LittleEndian<uint64_t> u64(big64);
|
||||||
return u64.raw_value;
|
// return u64.raw_value;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
/* it can be used in Windows 8
|
///* it can be used in Windows 8
|
||||||
#include <Winsock2.h>
|
//#include <Winsock2.h>
|
||||||
|
//
|
||||||
uint16_t htobe16(uint16_t int16)
|
//uint16_t htobe16(uint16_t int16)
|
||||||
{
|
//{
|
||||||
return htons(int16);
|
// return htons(int16);
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
uint32_t htobe32(uint32_t int32)
|
//uint32_t htobe32(uint32_t int32)
|
||||||
{
|
//{
|
||||||
return htonl(int32);
|
// return htonl(int32);
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
uint64_t htobe64(uint64_t int64)
|
//uint64_t htobe64(uint64_t int64)
|
||||||
{
|
//{
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
// // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
||||||
//return htonll(int64);
|
// //return htonll(int64);
|
||||||
return 0;
|
// return 0;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
uint16_t be16toh(uint16_t big16)
|
//uint16_t be16toh(uint16_t big16)
|
||||||
{
|
//{
|
||||||
return ntohs(big16);
|
// return ntohs(big16);
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
uint32_t be32toh(uint32_t big32)
|
//uint32_t be32toh(uint32_t big32)
|
||||||
{
|
//{
|
||||||
return ntohl(big32);
|
// return ntohl(big32);
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
uint64_t be64toh(uint64_t big64)
|
//uint64_t be64toh(uint64_t big64)
|
||||||
{
|
//{
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
// // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
||||||
//return ntohll(big64);
|
// //return ntohll(big64);
|
||||||
return 0;
|
// return 0;
|
||||||
}
|
//}
|
||||||
*/
|
//*/
|
16
I2PEndian.h
16
I2PEndian.h
|
@ -5,14 +5,16 @@
|
||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
#else
|
#else
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
//
|
||||||
|
//uint16_t htobe16(uint16_t int16);
|
||||||
|
//uint32_t htobe32(uint32_t int32);
|
||||||
|
//uint64_t htobe64(uint64_t int64);
|
||||||
|
//
|
||||||
|
//uint16_t be16toh(uint16_t big16);
|
||||||
|
//uint32_t be32toh(uint32_t big32);
|
||||||
|
//uint64_t be64toh(uint64_t big64);
|
||||||
|
|
||||||
uint16_t htobe16(uint16_t int16);
|
#include "portable_endian.h"
|
||||||
uint32_t htobe32(uint32_t int32);
|
|
||||||
uint64_t htobe64(uint64_t int64);
|
|
||||||
|
|
||||||
uint16_t be16toh(uint16_t big16);
|
|
||||||
uint32_t be32toh(uint32_t big32);
|
|
||||||
uint64_t be64toh(uint64_t big64);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
12
LeaseSet.cpp
12
LeaseSet.cpp
|
@ -3,6 +3,7 @@
|
||||||
#include "CryptoConst.h"
|
#include "CryptoConst.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
|
#include "NetDb.h"
|
||||||
#include "LeaseSet.h"
|
#include "LeaseSet.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
|
@ -28,6 +29,7 @@ namespace data
|
||||||
memcpy (m_EncryptionKey, header->encryptionKey, 256);
|
memcpy (m_EncryptionKey, header->encryptionKey, 256);
|
||||||
LogPrint ("LeaseSet num=", (int)header->num);
|
LogPrint ("LeaseSet num=", (int)header->num);
|
||||||
|
|
||||||
|
// process leases
|
||||||
const uint8_t * leases = buf + sizeof (H);
|
const uint8_t * leases = buf + sizeof (H);
|
||||||
for (int i = 0; i < header->num; i++)
|
for (int i = 0; i < header->num; i++)
|
||||||
{
|
{
|
||||||
|
@ -36,8 +38,16 @@ namespace data
|
||||||
lease.endDate = be64toh (lease.endDate);
|
lease.endDate = be64toh (lease.endDate);
|
||||||
m_Leases.push_back (lease);
|
m_Leases.push_back (lease);
|
||||||
leases += sizeof (Lease);
|
leases += sizeof (Lease);
|
||||||
}
|
|
||||||
|
|
||||||
|
// check if lease's gateway is in our netDb
|
||||||
|
if (!netdb.FindRouter (lease.tunnelGateway))
|
||||||
|
{
|
||||||
|
// if not found request it
|
||||||
|
LogPrint ("Lease's tunnel gateway not found. Requested");
|
||||||
|
netdb.RequestDestination (lease.tunnelGateway);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
CryptoPP::DSA::PublicKey pubKey;
|
CryptoPP::DSA::PublicKey pubKey;
|
||||||
pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag,
|
pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag,
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -3,9 +3,9 @@ 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 util.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 -lpthread
|
||||||
LIBS =
|
LIBS =
|
||||||
|
|
||||||
all: i2p
|
all: i2p
|
||||||
|
|
|
@ -517,10 +517,10 @@ namespace ntcp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NTCPClient::NTCPClient (boost::asio::io_service& service, const char * address,
|
NTCPClient::NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address,
|
||||||
int port, i2p::data::RouterInfo& in_RouterInfo):
|
int port, i2p::data::RouterInfo& in_RouterInfo):
|
||||||
NTCPSession (service, in_RouterInfo),
|
NTCPSession (service, in_RouterInfo),
|
||||||
m_Endpoint (boost::asio::ip::address::from_string (address), port)
|
m_Endpoint (address, port)
|
||||||
{
|
{
|
||||||
Connect ();
|
Connect ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,7 @@ namespace ntcp
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NTCPClient (boost::asio::io_service& service, const char * address, int port, i2p::data::RouterInfo& in_RouterInfo);
|
NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, i2p::data::RouterInfo& in_RouterInfo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
252
NetDb.cpp
252
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"
|
||||||
|
@ -8,6 +9,7 @@
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
#include "Tunnel.h"
|
#include "Tunnel.h"
|
||||||
|
#include "Transports.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
#include "Garlic.h"
|
#include "Garlic.h"
|
||||||
#include "NetDb.h"
|
#include "NetDb.h"
|
||||||
|
@ -29,6 +31,16 @@ namespace data
|
||||||
m_LastReplyTunnel = replyTunnel;
|
m_LastReplyTunnel = replyTunnel;
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
I2NPMessage * RequestedDestination::CreateRequestMessage (const IdentHash& floodfill)
|
||||||
|
{
|
||||||
|
I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination,
|
||||||
|
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
|
||||||
|
m_ExcludedPeers.insert (floodfill);
|
||||||
|
m_LastRouter = nullptr;
|
||||||
|
m_LastReplyTunnel = nullptr;
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
NetDb netdb;
|
NetDb netdb;
|
||||||
|
|
||||||
|
@ -165,63 +177,106 @@ namespace data
|
||||||
return it->second;
|
return it->second;
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Move to reseed and/or scheduled tasks. (In java version, scheduler fix this as well as sort RIs.)
|
||||||
|
bool NetDb::CreateNetDb(const char * directory)
|
||||||
|
{
|
||||||
|
boost::filesystem::path p (directory);
|
||||||
|
LogPrint (directory, " doesn't exist, trying to create it.");
|
||||||
|
if (!boost::filesystem::create_directory (p))
|
||||||
|
{
|
||||||
|
LogPrint("Failed to create directory ", directory);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// list of chars might appear in base64 string
|
||||||
|
const char * chars = GetBase64SubstitutionTable (); // 64 bytes
|
||||||
|
boost::filesystem::path suffix;
|
||||||
|
for (int i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
|
suffix = std::string ("/r") + chars[i];
|
||||||
|
#else
|
||||||
|
suffix = std::string ("\\r") + chars[i];
|
||||||
|
#endif
|
||||||
|
if (!boost::filesystem::create_directory( boost::filesystem::path (p / suffix) )) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void NetDb::Load (const char * directory)
|
void NetDb::Load (const char * directory)
|
||||||
{
|
{
|
||||||
boost::filesystem::path p (directory);
|
boost::filesystem::path p (directory);
|
||||||
if (boost::filesystem::exists (p))
|
if (!boost::filesystem::exists (p))
|
||||||
{
|
{
|
||||||
int numRouters = 0;
|
if (!CreateNetDb(directory)) return;
|
||||||
boost::filesystem::directory_iterator end;
|
}
|
||||||
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
|
// TODO: Reseed if needed.
|
||||||
|
int numRouters = 0;
|
||||||
|
boost::filesystem::directory_iterator end;
|
||||||
|
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
|
||||||
|
{
|
||||||
|
if (boost::filesystem::is_directory (it->status()))
|
||||||
{
|
{
|
||||||
if (boost::filesystem::is_directory (it->status()))
|
for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1)
|
||||||
{
|
{
|
||||||
for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1)
|
|
||||||
{
|
|
||||||
#if BOOST_VERSION > 10500
|
#if BOOST_VERSION > 10500
|
||||||
RouterInfo * r = new RouterInfo (it1->path().string().c_str ());
|
RouterInfo * r = new RouterInfo (it1->path().string().c_str ());
|
||||||
#else
|
#else
|
||||||
RouterInfo * r = new RouterInfo(it1->path().c_str());
|
RouterInfo * r = new RouterInfo(it1->path().c_str());
|
||||||
#endif
|
#endif
|
||||||
m_RouterInfos[r->GetIdentHash ()] = r;
|
m_RouterInfos[r->GetIdentHash ()] = r;
|
||||||
numRouters++;
|
numRouters++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrint (numRouters, " routers loaded");
|
|
||||||
}
|
}
|
||||||
else
|
LogPrint (numRouters, " routers loaded");
|
||||||
LogPrint (directory, " doesn't exist");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::SaveUpdated (const char * directory)
|
void NetDb::SaveUpdated (const char * directory)
|
||||||
{
|
{
|
||||||
auto GetFilePath = [](const char * directory, const RouterInfo * routerInfo)
|
auto GetFilePath = [](const char * directory, const RouterInfo * routerInfo)
|
||||||
{
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
return std::string (directory) + "/r" +
|
return std::string (directory) + "/r" +
|
||||||
routerInfo->GetIdentHashBase64 ()[0] + "/routerInfo-" +
|
routerInfo->GetIdentHashBase64 ()[0] + "/routerInfo-" +
|
||||||
|
#else
|
||||||
|
return std::string (directory) + "\\r" +
|
||||||
|
routerInfo->GetIdentHashBase64 ()[0] + "\\routerInfo-" +
|
||||||
|
#endif
|
||||||
routerInfo->GetIdentHashBase64 () + ".dat";
|
routerInfo->GetIdentHashBase64 () + ".dat";
|
||||||
};
|
};
|
||||||
|
|
||||||
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 ())
|
||||||
{
|
{
|
||||||
std::ofstream r (GetFilePath(directory, it.second));
|
std::ofstream r (GetFilePath(directory, it.second), std::ofstream::binary);
|
||||||
r.write ((char *)it.second->GetBuffer (), it.second->GetBufferLen ());
|
r.write ((char *)it.second->GetBuffer (), it.second->GetBufferLen ());
|
||||||
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,32 +294,49 @@ namespace data
|
||||||
|
|
||||||
void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet)
|
void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet)
|
||||||
{
|
{
|
||||||
auto floodfill= GetRandomNTCPRouter (true);
|
if (isLeaseSet) // we request LeaseSet through tunnels
|
||||||
if (floodfill)
|
{
|
||||||
RequestDestination (destination, floodfill, isLeaseSet);
|
i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel ();
|
||||||
else
|
if (outbound)
|
||||||
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)
|
|
||||||
{
|
|
||||||
i2p::tunnel::InboundTunnel * inbound = i2p::tunnel::tunnels.GetNextInboundTunnel ();
|
|
||||||
if (inbound)
|
|
||||||
{
|
{
|
||||||
RequestedDestination * dest = CreateRequestedDestination (destination, isLeaseSet);
|
i2p::tunnel::InboundTunnel * inbound = i2p::tunnel::tunnels.GetNextInboundTunnel ();
|
||||||
dest->SetLastOutboundTunnel (outbound);
|
if (inbound)
|
||||||
auto msg = dest->CreateRequestMessage (floodfill, inbound);
|
{
|
||||||
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg);
|
RequestedDestination * dest = CreateRequestedDestination (destination, isLeaseSet);
|
||||||
}
|
auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
|
||||||
|
if (floodfill)
|
||||||
|
{
|
||||||
|
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||||
|
// 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
|
||||||
|
LogPrint ("No inbound tunnels found");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("No inbound tunnels found");
|
LogPrint ("No outbound tunnels found");
|
||||||
}
|
}
|
||||||
else
|
else // RouterInfo is requested directly
|
||||||
LogPrint ("No outbound tunnels found");
|
{
|
||||||
|
RequestedDestination * dest = CreateRequestedDestination (destination, false);
|
||||||
|
auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
|
||||||
|
if (floodfill)
|
||||||
|
{
|
||||||
|
dest->SetLastOutboundTunnel (nullptr);
|
||||||
|
i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::HandleDatabaseStoreMsg (uint8_t * buf, size_t len)
|
void NetDb::HandleDatabaseStoreMsg (uint8_t * buf, size_t len)
|
||||||
|
@ -377,18 +449,25 @@ namespace data
|
||||||
dest->GetLastRouter ()->GetIdentHash (), 0, msg
|
dest->GetLastRouter ()->GetIdentHash (), 0, msg
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else // we should send directly
|
||||||
|
{
|
||||||
|
if (!dest->IsLeaseSet ()) // if not LeaseSet
|
||||||
|
i2p::transports.SendMessage (router, dest->CreateRequestMessage (router));
|
||||||
|
else
|
||||||
|
LogPrint ("Can't request LeaseSet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msgs.size () > 0)
|
if (outbound && msgs.size () > 0)
|
||||||
outbound->SendTunnelDataMsg (msgs);
|
outbound->SendTunnelDataMsg (msgs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// no more requests for detination possible. delete it
|
// no more requests for detination possible. delete it
|
||||||
m_RequestedDestinations.erase (it);
|
|
||||||
delete it->second;
|
delete it->second;
|
||||||
|
m_RequestedDestinations.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -402,7 +481,7 @@ namespace data
|
||||||
auto inbound = i2p::tunnel::tunnels.GetNextInboundTunnel ();
|
auto inbound = i2p::tunnel::tunnels.GetNextInboundTunnel ();
|
||||||
if (outbound && inbound)
|
if (outbound && inbound)
|
||||||
{
|
{
|
||||||
auto floodfill = GetRandomNTCPRouter (true);
|
auto floodfill = GetRandomRouter (outbound->GetEndpointRouter (), true);
|
||||||
if (floodfill)
|
if (floodfill)
|
||||||
{
|
{
|
||||||
LogPrint ("Exploring new routers ...");
|
LogPrint ("Exploring new routers ...");
|
||||||
|
@ -449,8 +528,8 @@ namespace data
|
||||||
auto it = m_RequestedDestinations.find (dest);
|
auto it = m_RequestedDestinations.find (dest);
|
||||||
if (it != m_RequestedDestinations.end ())
|
if (it != m_RequestedDestinations.end ())
|
||||||
{
|
{
|
||||||
m_RequestedDestinations.erase (it);
|
|
||||||
delete it->second;
|
delete it->second;
|
||||||
|
m_RequestedDestinations.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,16 +549,29 @@ namespace data
|
||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RouterInfo * NetDb::GetRandomRouter () const
|
const RouterInfo * NetDb::GetRandomRouter (const RouterInfo * compatibleWith, bool floodfillOnly) const
|
||||||
{
|
{
|
||||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1), i = 0;
|
uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1);
|
||||||
for (auto it: m_RouterInfos)
|
for (int j = 0; j < 2; j++)
|
||||||
{
|
{
|
||||||
if (i >= ind) return it.second;
|
uint32_t i = 0;
|
||||||
else i++;
|
for (auto it: m_RouterInfos)
|
||||||
|
{
|
||||||
|
if (i >= ind)
|
||||||
|
{
|
||||||
|
if (!it.second->IsUnreachable () &&
|
||||||
|
(!compatibleWith || it.second->IsCompatible (*compatibleWith)) &&
|
||||||
|
(!floodfillOnly || it.second->IsFloodfill ()))
|
||||||
|
return it.second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
// we couldn't find anything, try second pass
|
||||||
|
ind = 0;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr; // seem we have too few routers
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::PostI2NPMsg (I2NPMessage * msg)
|
void NetDb::PostI2NPMsg (I2NPMessage * msg)
|
||||||
|
@ -487,7 +579,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 +588,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 +600,46 @@ namespace data
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Move to reseed.
|
||||||
|
//TODO: Implement v1 & v2 reseeding. Lightweight zip library is needed for v2.
|
||||||
|
// orignal: zip is part of crypto++, see implementation of DatabaseStoreMsg
|
||||||
|
//TODO: Implement SU3, utils.
|
||||||
|
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 ());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
NetDb.h
16
NetDb.h
|
@ -26,12 +26,15 @@ 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 IsLeaseSet () const { return m_IsLeaseSet; };
|
||||||
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
|
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
|
||||||
I2NPMessage * CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel);
|
I2NPMessage * CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel);
|
||||||
|
I2NPMessage * CreateRequestMessage (const IdentHash& floodfill);
|
||||||
|
|
||||||
i2p::tunnel::OutboundTunnel * GetLastOutboundTunnel () const { return m_LastOutboundTunnel; };
|
i2p::tunnel::OutboundTunnel * GetLastOutboundTunnel () const { return m_LastOutboundTunnel; };
|
||||||
void SetLastOutboundTunnel (i2p::tunnel::OutboundTunnel * tunnel) { m_LastOutboundTunnel = tunnel; };
|
void SetLastOutboundTunnel (i2p::tunnel::OutboundTunnel * tunnel) { m_LastOutboundTunnel = tunnel; };
|
||||||
|
|
||||||
|
@ -62,23 +65,24 @@ 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);
|
||||||
|
|
||||||
const RouterInfo * GetRandomNTCPRouter (bool floodfillOnly = false) const;
|
const RouterInfo * GetRandomNTCPRouter (bool floodfillOnly = false) const;
|
||||||
const RouterInfo * GetRandomRouter () const;
|
const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith = nullptr, bool floodfillOnly = false) const;
|
||||||
|
|
||||||
void PostI2NPMsg (I2NPMessage * msg);
|
void PostI2NPMsg (I2NPMessage * msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
bool CreateNetDb(const char * directory);
|
||||||
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);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <cryptopp/dsa.h>
|
#include <cryptopp/dsa.h>
|
||||||
#include "CryptoConst.h"
|
#include "CryptoConst.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
|
@ -45,7 +46,7 @@ namespace i2p
|
||||||
auto address = m_RouterInfo.GetNTCPAddress ();
|
auto address = m_RouterInfo.GetNTCPAddress ();
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
address->host = host;
|
address->host = boost::asio::ip::address::from_string (host);
|
||||||
address->port = port;
|
address->port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ namespace i2p
|
||||||
|
|
||||||
bool RouterContext::Load ()
|
bool RouterContext::Load ()
|
||||||
{
|
{
|
||||||
std::ifstream fk (ROUTER_KEYS);
|
std::ifstream fk (ROUTER_KEYS, std::ifstream::binary | std::ofstream::in);
|
||||||
if (!fk.is_open ()) return false;
|
if (!fk.is_open ()) return false;
|
||||||
|
|
||||||
fk.read ((char *)&m_Keys, sizeof (m_Keys));
|
fk.read ((char *)&m_Keys, sizeof (m_Keys));
|
||||||
|
@ -74,10 +75,10 @@ namespace i2p
|
||||||
|
|
||||||
void RouterContext::Save ()
|
void RouterContext::Save ()
|
||||||
{
|
{
|
||||||
std::ofstream fk (ROUTER_KEYS);
|
std::ofstream fk (ROUTER_KEYS, std::ofstream::binary | std::ofstream::out);
|
||||||
fk.write ((char *)&m_Keys, sizeof (m_Keys));
|
fk.write ((char *)&m_Keys, sizeof (m_Keys));
|
||||||
|
|
||||||
std::ofstream fi (ROUTER_INFO);
|
std::ofstream fi (ROUTER_INFO, std::ofstream::binary | std::ofstream::out);
|
||||||
fi.write ((char *)m_RouterInfo.GetBuffer (), m_RouterInfo.GetBufferLen ());
|
fi.write ((char *)m_RouterInfo.GetBuffer (), m_RouterInfo.GetBufferLen ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,18 +12,19 @@
|
||||||
#include "RouterInfo.h"
|
#include "RouterInfo.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
RouterInfo::RouterInfo (const char * filename):
|
RouterInfo::RouterInfo (const char * filename):
|
||||||
m_IsUpdated (false), m_IsUnreachable (false)
|
m_IsUpdated (false), m_IsUnreachable (false), m_SupportedTransports (0)
|
||||||
{
|
{
|
||||||
ReadFromFile (filename);
|
ReadFromFile (filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
RouterInfo::RouterInfo (const uint8_t * buf, int len):
|
RouterInfo::RouterInfo (const uint8_t * buf, int len):
|
||||||
m_IsUpdated (true)
|
m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0)
|
||||||
{
|
{
|
||||||
memcpy (m_Buffer, buf, len);
|
memcpy (m_Buffer, buf, len);
|
||||||
m_BufferLen = len;
|
m_BufferLen = len;
|
||||||
|
@ -41,7 +42,7 @@ namespace data
|
||||||
|
|
||||||
void RouterInfo::ReadFromFile (const char * filename)
|
void RouterInfo::ReadFromFile (const char * filename)
|
||||||
{
|
{
|
||||||
std::ifstream s(filename);
|
std::ifstream s(filename, std::ifstream::binary);
|
||||||
if (s.is_open ())
|
if (s.is_open ())
|
||||||
{
|
{
|
||||||
s.seekg (0,std::ios::end);
|
s.seekg (0,std::ios::end);
|
||||||
|
@ -95,15 +96,34 @@ namespace data
|
||||||
size = be16toh (size);
|
size = be16toh (size);
|
||||||
while (r < size)
|
while (r < size)
|
||||||
{
|
{
|
||||||
char key[50], value[50];
|
char key[500], value[500];
|
||||||
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);
|
||||||
s.seekg (1, std::ios_base::cur); r++; // ;
|
s.seekg (1, std::ios_base::cur); r++; // ;
|
||||||
if (!strcmp (key, "host"))
|
if (!strcmp (key, "host"))
|
||||||
address.host = value;
|
{
|
||||||
|
boost::system::error_code ecode;
|
||||||
|
address.host = boost::asio::ip::address::from_string (value, ecode);
|
||||||
|
if (ecode)
|
||||||
|
{
|
||||||
|
// TODO: we should try to resolve address here
|
||||||
|
LogPrint ("Unexpected address ", value);
|
||||||
|
SetUnreachable (true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// add supported protocol
|
||||||
|
if (address.host.is_v4 ())
|
||||||
|
m_SupportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
|
||||||
|
else
|
||||||
|
m_SupportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (!strcmp (key, "port"))
|
else if (!strcmp (key, "port"))
|
||||||
address.port = boost::lexical_cast<int>(value);
|
address.port = boost::lexical_cast<int>(value);
|
||||||
|
else if (!strcmp (key, "key"))
|
||||||
|
Base64ToByteStream (value, strlen (value), address.key, 32);
|
||||||
}
|
}
|
||||||
m_Addresses.push_back(address);
|
m_Addresses.push_back(address);
|
||||||
}
|
}
|
||||||
|
@ -117,7 +137,13 @@ namespace data
|
||||||
size = be16toh (size);
|
size = be16toh (size);
|
||||||
while (r < 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];
|
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);
|
||||||
|
@ -166,7 +192,7 @@ namespace data
|
||||||
std::stringstream properties;
|
std::stringstream properties;
|
||||||
WriteString ("host", properties);
|
WriteString ("host", properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
WriteString (address.host, properties);
|
WriteString (address.host.to_string (), properties);
|
||||||
properties << ';';
|
properties << ';';
|
||||||
WriteString ("port", properties);
|
WriteString ("port", properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
|
@ -227,7 +253,7 @@ namespace data
|
||||||
void RouterInfo::AddNTCPAddress (const char * host, int port)
|
void RouterInfo::AddNTCPAddress (const char * host, int port)
|
||||||
{
|
{
|
||||||
Address addr;
|
Address addr;
|
||||||
addr.host = host;
|
addr.host = boost::asio::ip::address::from_string (host);
|
||||||
addr.port = port;
|
addr.port = port;
|
||||||
addr.transportStyle = eTransportNTCP;
|
addr.transportStyle = eTransportNTCP;
|
||||||
addr.cost = 2;
|
addr.cost = 2;
|
||||||
|
@ -256,22 +282,33 @@ namespace data
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterInfo::IsNTCP () const
|
bool RouterInfo::IsNTCP (bool v4only) const
|
||||||
{
|
{
|
||||||
for (auto& address : m_Addresses)
|
if (v4only)
|
||||||
{
|
return m_SupportedTransports & eNTCPV4;
|
||||||
if (address.transportStyle == eTransportNTCP)
|
else
|
||||||
return true;
|
return m_SupportedTransports & (eNTCPV4 | eNTCPV6);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only)
|
||||||
|
{
|
||||||
|
return GetAddress (eTransportNTCP, v4only);
|
||||||
}
|
}
|
||||||
|
|
||||||
RouterInfo::Address * RouterInfo::GetNTCPAddress ()
|
RouterInfo::Address * RouterInfo::GetSSUAddress (bool v4only)
|
||||||
|
{
|
||||||
|
return GetAddress (eTransportSSU, v4only);
|
||||||
|
}
|
||||||
|
|
||||||
|
RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only)
|
||||||
{
|
{
|
||||||
for (auto& address : m_Addresses)
|
for (auto& address : m_Addresses)
|
||||||
{
|
{
|
||||||
if (address.transportStyle == eTransportNTCP)
|
if (address.transportStyle == s)
|
||||||
return &address;
|
{
|
||||||
|
if (!v4only || address.host.is_v4 ())
|
||||||
|
return &address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
20
RouterInfo.h
20
RouterInfo.h
|
@ -17,6 +17,14 @@ namespace data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum SupportedTranports
|
||||||
|
{
|
||||||
|
eNTCPV4 = 0x01,
|
||||||
|
eNTCPV6 = 0x20,
|
||||||
|
eSSUV4 = 0x40,
|
||||||
|
eSSUV6 = 0x80
|
||||||
|
};
|
||||||
|
|
||||||
enum TransportStyle
|
enum TransportStyle
|
||||||
{
|
{
|
||||||
eTransportUnknown = 0,
|
eTransportUnknown = 0,
|
||||||
|
@ -27,10 +35,11 @@ namespace data
|
||||||
struct Address
|
struct Address
|
||||||
{
|
{
|
||||||
TransportStyle transportStyle;
|
TransportStyle transportStyle;
|
||||||
std::string host;
|
boost::asio::ip::address host;
|
||||||
int port;
|
int port;
|
||||||
uint64_t date;
|
uint64_t date;
|
||||||
uint8_t cost;
|
uint8_t cost;
|
||||||
|
uint8_t key[32]; // into key for SSU
|
||||||
};
|
};
|
||||||
|
|
||||||
RouterInfo (const char * filename);
|
RouterInfo (const char * filename);
|
||||||
|
@ -45,14 +54,17 @@ namespace data
|
||||||
const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; };
|
const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; };
|
||||||
uint64_t GetTimestamp () const { return m_Timestamp; };
|
uint64_t GetTimestamp () const { return m_Timestamp; };
|
||||||
const std::vector<Address>& GetAddresses () const { return m_Addresses; };
|
const std::vector<Address>& GetAddresses () const { return m_Addresses; };
|
||||||
Address * GetNTCPAddress ();
|
Address * GetNTCPAddress (bool v4only = true);
|
||||||
|
Address * GetSSUAddress (bool v4only = true);
|
||||||
const RoutingKey& GetRoutingKey () const { return m_RoutingKey; };
|
const RoutingKey& GetRoutingKey () const { return m_RoutingKey; };
|
||||||
|
|
||||||
void AddNTCPAddress (const char * host, int port);
|
void AddNTCPAddress (const char * host, int port);
|
||||||
void SetProperty (const char * key, const char * value);
|
void SetProperty (const char * key, const char * value);
|
||||||
const char * GetProperty (const char * key) const;
|
const char * GetProperty (const char * key) const;
|
||||||
bool IsFloodfill () const;
|
bool IsFloodfill () const;
|
||||||
bool IsNTCP () const;
|
bool IsNTCP (bool v4only = true) const;
|
||||||
|
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
|
||||||
|
|
||||||
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
||||||
bool IsUnreachable () const { return m_IsUnreachable; };
|
bool IsUnreachable () const { return m_IsUnreachable; };
|
||||||
|
|
||||||
|
@ -78,6 +90,7 @@ namespace data
|
||||||
size_t ReadString (char * str, std::istream& s);
|
size_t ReadString (char * str, std::istream& s);
|
||||||
void WriteString (const std::string& str, std::ostream& s);
|
void WriteString (const std::string& str, std::ostream& s);
|
||||||
void UpdateIdentHashBase64 ();
|
void UpdateIdentHashBase64 ();
|
||||||
|
Address * GetAddress (TransportStyle s, bool v4only);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -91,6 +104,7 @@ namespace data
|
||||||
std::vector<Address> m_Addresses;
|
std::vector<Address> m_Addresses;
|
||||||
std::map<std::string, std::string> m_Properties;
|
std::map<std::string, std::string> m_Properties;
|
||||||
bool m_IsUpdated, m_IsUnreachable;
|
bool m_IsUpdated, m_IsUnreachable;
|
||||||
|
uint8_t m_SupportedTransports;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
294
SSU.cpp
Normal file
294
SSU.cpp
Normal file
|
@ -0,0 +1,294 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <cryptopp/dh.h>
|
||||||
|
#include <cryptopp/secblock.h>
|
||||||
|
#include "CryptoConst.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "Timestamp.h"
|
||||||
|
#include "RouterContext.h"
|
||||||
|
#include "hmac.h"
|
||||||
|
#include "SSU.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace ssu
|
||||||
|
{
|
||||||
|
|
||||||
|
SSUSession::SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint,
|
||||||
|
i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint),
|
||||||
|
m_RemoteRouter (router), m_State (eSessionStateUnknown)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::CreateAESKey (uint8_t * pubKey, uint8_t * aesKey) // TODO: move it to base class for NTCP and SSU
|
||||||
|
{
|
||||||
|
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||||
|
CryptoPP::SecByteBlock secretKey(dh.AgreedValueLength());
|
||||||
|
if (!dh.Agree (secretKey, i2p::context.GetPrivateKey (), pubKey))
|
||||||
|
{
|
||||||
|
LogPrint ("Couldn't create shared key");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (secretKey[0] & 0x80)
|
||||||
|
{
|
||||||
|
aesKey[0] = 0;
|
||||||
|
memcpy (aesKey + 1, secretKey, 31);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy (aesKey, secretKey, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||||
|
{
|
||||||
|
switch (m_State)
|
||||||
|
{
|
||||||
|
case eSessionStateUnknown:
|
||||||
|
// session request
|
||||||
|
ProcessSessionRequest (buf, len, senderEndpoint);
|
||||||
|
break;
|
||||||
|
case eSessionStateRequestSent:
|
||||||
|
// session created
|
||||||
|
ProcessSessionCreated (buf, len);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogPrint ("SSU state not implemented yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||||
|
{
|
||||||
|
LogPrint ("Process session request");
|
||||||
|
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, buf, len))
|
||||||
|
{
|
||||||
|
m_State = eSessionStateRequestReceived;
|
||||||
|
LogPrint ("Session request received");
|
||||||
|
SendSessionCreated (senderEndpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
LogPrint ("Process session created");
|
||||||
|
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, buf, len))
|
||||||
|
{
|
||||||
|
m_State = eSessionStateCreatedReceived;
|
||||||
|
LogPrint ("Session request received");
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::SendSessionRequest ()
|
||||||
|
{
|
||||||
|
auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr;
|
||||||
|
if (!address)
|
||||||
|
{
|
||||||
|
LogPrint ("Missing remote SSU address");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t buf[304 + 18]; // 304 bytes for ipv4 (320 for ipv6)
|
||||||
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
|
memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256);
|
||||||
|
payload[256] = 4; // we assume ipv4
|
||||||
|
*(uint32_t *)(payload + 257) = address->host.to_v4 ().to_ulong (); // network bytes order already
|
||||||
|
|
||||||
|
uint8_t iv[16];
|
||||||
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
|
rnd.GenerateBlock (iv, 16); // random iv
|
||||||
|
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, 304, address->key, iv, address->key);
|
||||||
|
|
||||||
|
m_State = eSessionStateRequestSent;
|
||||||
|
m_Server->Send (buf, 304, m_RemoteEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::SendSessionCreated (const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||||
|
{
|
||||||
|
auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr;
|
||||||
|
if (!address)
|
||||||
|
{
|
||||||
|
LogPrint ("Missing remote SSU address");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t buf[368 + 18];
|
||||||
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
|
memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256);
|
||||||
|
|
||||||
|
m_State = eSessionStateRequestSent;
|
||||||
|
m_Server->Send (buf, 368, m_RemoteEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
|
||||||
|
if (address)
|
||||||
|
{
|
||||||
|
// use intro key for verification and decryption
|
||||||
|
if (Validate (buf, len, address->key))
|
||||||
|
{
|
||||||
|
Decrypt (buf, len, address->key);
|
||||||
|
SSUHeader * header = (SSUHeader *)buf;
|
||||||
|
if ((header->flag >> 4) == expectedPayloadType)
|
||||||
|
{
|
||||||
|
CreateAESKey (buf + sizeof (SSUHeader), m_SessionKey);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint ("Unexpected payload type ", (int)(header->flag >> 4));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint ("MAC verifcation failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint ("SSU is not supported");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey)
|
||||||
|
{
|
||||||
|
if (len < sizeof (SSUHeader))
|
||||||
|
{
|
||||||
|
LogPrint ("Unexpected SSU packet length ", len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SSUHeader * header = (SSUHeader *)buf;
|
||||||
|
memcpy (header->iv, iv, 16);
|
||||||
|
header->flag = payloadType << 4; // MSB is 0
|
||||||
|
header->time = htobe32 (i2p::util::GetSecondsSinceEpoch ());
|
||||||
|
uint8_t * encrypted = &header->flag;
|
||||||
|
uint16_t encryptedLen = len - (encrypted - buf);
|
||||||
|
m_Encryption.SetKeyWithIV (aesKey, 32, iv);
|
||||||
|
m_Encryption.ProcessData (encrypted, encrypted, encryptedLen);
|
||||||
|
// assume actual buffer size is 18 (16 + 2) bytes more
|
||||||
|
memcpy (buf + len, iv, 16);
|
||||||
|
*(uint16_t *)(buf + len + 16) = htobe16 (encryptedLen);
|
||||||
|
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, header->mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey)
|
||||||
|
{
|
||||||
|
if (len < sizeof (SSUHeader))
|
||||||
|
{
|
||||||
|
LogPrint ("Unexpected SSU packet length ", len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SSUHeader * header = (SSUHeader *)buf;
|
||||||
|
uint8_t * encrypted = &header->flag;
|
||||||
|
uint16_t encryptedLen = len - (encrypted - buf);
|
||||||
|
m_Decryption.SetKeyWithIV (aesKey, 32, header->iv);
|
||||||
|
m_Decryption.ProcessData (encrypted, encrypted, encryptedLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SSUSession::Validate (uint8_t * buf, size_t len, uint8_t * macKey)
|
||||||
|
{
|
||||||
|
if (len < sizeof (SSUHeader))
|
||||||
|
{
|
||||||
|
LogPrint ("Unexpected SSU packet length ", len);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SSUHeader * header = (SSUHeader *)buf;
|
||||||
|
uint8_t * encrypted = &header->flag;
|
||||||
|
uint16_t encryptedLen = len - (encrypted - buf);
|
||||||
|
// assume actual buffer size is 18 (16 + 2) bytes more
|
||||||
|
memcpy (buf + len, header->iv, 16);
|
||||||
|
*(uint16_t *)(buf + len + 16) = htobe16 (encryptedLen);
|
||||||
|
uint8_t digest[16];
|
||||||
|
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, digest);
|
||||||
|
return !memcmp (header->mac, digest, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::Connect ()
|
||||||
|
{
|
||||||
|
SendSessionRequest ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::SendI2NPMessage (I2NPMessage * msg)
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
SSUServer::SSUServer (boost::asio::io_service& service, int port):
|
||||||
|
m_Socket (service, boost::asio::ip::udp::endpoint (boost::asio::ip::udp::v4 (), port))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SSUServer::~SSUServer ()
|
||||||
|
{
|
||||||
|
for (auto it: m_Sessions)
|
||||||
|
delete it.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUServer::Start ()
|
||||||
|
{
|
||||||
|
Receive ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUServer::Stop ()
|
||||||
|
{
|
||||||
|
m_Socket.close ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUServer::Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to)
|
||||||
|
{
|
||||||
|
m_Socket.send_to (boost::asio::buffer (buf, len), to);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
SSUSession * session = nullptr;
|
||||||
|
auto it = m_Sessions.find (m_SenderEndpoint);
|
||||||
|
if (it != m_Sessions.end ())
|
||||||
|
session = it->second;
|
||||||
|
if (!session)
|
||||||
|
{
|
||||||
|
session = new SSUSession (this, m_SenderEndpoint);
|
||||||
|
m_Sessions[m_SenderEndpoint] = session;
|
||||||
|
LogPrint ("New SSU session from ", m_SenderEndpoint.address ().to_string (), ":", m_SenderEndpoint.port (), " created");
|
||||||
|
}
|
||||||
|
session->ProcessNextMessage (m_ReceiveBuffer, bytes_transferred, m_SenderEndpoint);
|
||||||
|
Receive ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint ("SSU receive error: ", ecode.message ());
|
||||||
|
}
|
||||||
|
|
||||||
|
SSUSession * SSUServer::GetSession (i2p::data::RouterInfo * router)
|
||||||
|
{
|
||||||
|
SSUSession * session = nullptr;
|
||||||
|
if (router)
|
||||||
|
{
|
||||||
|
auto address = router->GetSSUAddress ();
|
||||||
|
if (address)
|
||||||
|
{
|
||||||
|
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
|
||||||
|
auto it = m_Sessions.find (remoteEndpoint);
|
||||||
|
if (it != m_Sessions.end ())
|
||||||
|
session = it->second;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// otherwise create new session
|
||||||
|
session = new SSUSession (this, remoteEndpoint, router);
|
||||||
|
m_Sessions[remoteEndpoint] = session;
|
||||||
|
LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ",
|
||||||
|
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created");
|
||||||
|
session->Connect ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint ("Router ", router->GetIdentHashAbbreviation (), " doesn't have SSU address");
|
||||||
|
}
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
116
SSU.h
Normal file
116
SSU.h
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
#ifndef SSU_H__
|
||||||
|
#define SSU_H__
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <map>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <cryptopp/modes.h>
|
||||||
|
#include <cryptopp/aes.h>
|
||||||
|
#include "I2PEndian.h"
|
||||||
|
#include "RouterInfo.h"
|
||||||
|
#include "I2NPProtocol.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace ssu
|
||||||
|
{
|
||||||
|
#pragma pack(1)
|
||||||
|
struct SSUHeader
|
||||||
|
{
|
||||||
|
uint8_t mac[16];
|
||||||
|
uint8_t iv[16];
|
||||||
|
uint8_t flag;
|
||||||
|
uint32_t time;
|
||||||
|
};
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
const int SSU_MTU = 1484;
|
||||||
|
|
||||||
|
// payload types (3 bits)
|
||||||
|
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
|
||||||
|
const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1;
|
||||||
|
const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2;
|
||||||
|
const uint8_t PAYLOAD_TYPE_RELAY_REQUEST = 3;
|
||||||
|
const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4;
|
||||||
|
const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
|
||||||
|
const uint8_t PAYLOAD_TYPE_DATA = 6;
|
||||||
|
const uint8_t PAYLOAD_TYPE_TEST = 7;
|
||||||
|
|
||||||
|
enum SessionState
|
||||||
|
{
|
||||||
|
eSessionStateUnknown,
|
||||||
|
eSessionStateRequestSent,
|
||||||
|
eSessionStateRequestReceived,
|
||||||
|
eSessionStateCreatedSent,
|
||||||
|
eSessionStateCreatedReceived,
|
||||||
|
eSessionStateConfirmedSent,
|
||||||
|
eSessionStateConfirmedReceived,
|
||||||
|
eSessionStateEstablised
|
||||||
|
};
|
||||||
|
|
||||||
|
class SSUServer;
|
||||||
|
class SSUSession
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint,
|
||||||
|
i2p::data::RouterInfo * router = nullptr);
|
||||||
|
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
||||||
|
|
||||||
|
void Connect ();
|
||||||
|
void SendI2NPMessage (I2NPMessage * msg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void CreateAESKey (uint8_t * pubKey, uint8_t * aesKey); // TODO: shouldn't be here
|
||||||
|
|
||||||
|
void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
||||||
|
void SendSessionRequest ();
|
||||||
|
void ProcessSessionCreated (uint8_t * buf, size_t len);
|
||||||
|
void SendSessionCreated (const boost::asio::ip::udp::endpoint& senderEndpoint);
|
||||||
|
|
||||||
|
bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len);
|
||||||
|
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey);
|
||||||
|
void Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey);
|
||||||
|
bool Validate (uint8_t * buf, size_t len, uint8_t * macKey);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
SSUServer * m_Server;
|
||||||
|
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
||||||
|
i2p::data::RouterInfo * m_RemoteRouter;
|
||||||
|
SessionState m_State;
|
||||||
|
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption;
|
||||||
|
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption;
|
||||||
|
uint8_t m_SessionKey[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
class SSUServer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
SSUServer (boost::asio::io_service& service, int port);
|
||||||
|
~SSUServer ();
|
||||||
|
void Start ();
|
||||||
|
void Stop ();
|
||||||
|
SSUSession * GetSession (i2p::data::RouterInfo * router);
|
||||||
|
|
||||||
|
void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
|
||||||
|
|
||||||
|
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[2*SSU_MTU];
|
||||||
|
std::map<boost::asio::ip::udp::endpoint, SSUSession *> m_Sessions;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#include "I2PEndian.h"
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cryptopp/gzip.h>
|
#include <cryptopp/gzip.h>
|
||||||
|
@ -26,30 +25,18 @@ namespace stream
|
||||||
{
|
{
|
||||||
while (auto packet = m_ReceiveQueue.Get ())
|
while (auto packet = m_ReceiveQueue.Get ())
|
||||||
delete packet;
|
delete packet;
|
||||||
|
for (auto it: m_SavedPackets)
|
||||||
|
delete it;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::HandleNextPacket (Packet * packet)
|
void Stream::HandleNextPacket (Packet * packet)
|
||||||
{
|
{
|
||||||
const uint8_t * buf = packet->buf;
|
|
||||||
buf += 4; // sendStreamID
|
|
||||||
if (!m_SendStreamID)
|
if (!m_SendStreamID)
|
||||||
m_SendStreamID = be32toh (*(uint32_t *)buf);
|
m_SendStreamID = packet->GetReceiveStreamID ();
|
||||||
buf += 4; // receiveStreamID
|
|
||||||
uint32_t receivedSeqn = be32toh (*(uint32_t *)buf);
|
|
||||||
buf += 4; // sequenceNum
|
|
||||||
buf += 4; // ackThrough
|
|
||||||
int nackCount = buf[0];
|
|
||||||
buf++; // NACK count
|
|
||||||
buf += 4*nackCount; // NACKs
|
|
||||||
buf++; // resendDelay
|
|
||||||
uint16_t flags = be16toh (*(uint16_t *)buf);
|
|
||||||
buf += 2; // flags
|
|
||||||
uint16_t optionalSize = be16toh (*(uint16_t *)buf);
|
|
||||||
buf += 2; // optional size
|
|
||||||
const uint8_t * optionalData = buf;
|
|
||||||
buf += optionalSize;
|
|
||||||
|
|
||||||
// process flags
|
// process flags
|
||||||
|
uint16_t flags = packet->GetFlags ();
|
||||||
|
const uint8_t * optionData = packet->GetOptionData ();
|
||||||
if (flags & PACKET_FLAG_SYNCHRONIZE)
|
if (flags & PACKET_FLAG_SYNCHRONIZE)
|
||||||
{
|
{
|
||||||
LogPrint ("Synchronize");
|
LogPrint ("Synchronize");
|
||||||
|
@ -58,21 +45,21 @@ namespace stream
|
||||||
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
||||||
{
|
{
|
||||||
LogPrint ("Signature");
|
LogPrint ("Signature");
|
||||||
optionalData += 40;
|
optionData += 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & PACKET_FLAG_FROM_INCLUDED)
|
if (flags & PACKET_FLAG_FROM_INCLUDED)
|
||||||
{
|
{
|
||||||
LogPrint ("From identity");
|
LogPrint ("From identity");
|
||||||
optionalData += sizeof (i2p::data::Identity);
|
optionData += sizeof (i2p::data::Identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have reached payload section
|
uint32_t receivedSeqn = packet->GetSeqn ();
|
||||||
LogPrint ("seqn=", receivedSeqn, ", flags=", flags);
|
LogPrint ("seqn=", receivedSeqn, ", flags=", flags);
|
||||||
if (!receivedSeqn || receivedSeqn == m_LastReceivedSequenceNumber + 1)
|
if (!receivedSeqn || receivedSeqn == m_LastReceivedSequenceNumber + 1)
|
||||||
{
|
{
|
||||||
// we have received next message
|
// we have received next message
|
||||||
packet->offset = buf - packet->buf;
|
packet->offset = packet->GetPayload () - packet->buf;
|
||||||
if (packet->GetLength () > 0)
|
if (packet->GetLength () > 0)
|
||||||
m_ReceiveQueue.Put (packet);
|
m_ReceiveQueue.Put (packet);
|
||||||
else
|
else
|
||||||
|
@ -80,6 +67,26 @@ namespace stream
|
||||||
|
|
||||||
m_LastReceivedSequenceNumber = receivedSeqn;
|
m_LastReceivedSequenceNumber = receivedSeqn;
|
||||||
SendQuickAck ();
|
SendQuickAck ();
|
||||||
|
|
||||||
|
// we should also try stored messages if any
|
||||||
|
for (auto it = m_SavedPackets.begin (); it != m_SavedPackets.end ();)
|
||||||
|
{
|
||||||
|
if ((*it)->GetSeqn () == m_LastReceivedSequenceNumber + 1)
|
||||||
|
{
|
||||||
|
Packet * packet = *it;
|
||||||
|
m_SavedPackets.erase (it++);
|
||||||
|
|
||||||
|
LogPrint ("Process saved packet seqn=", packet->GetSeqn ());
|
||||||
|
if (packet->GetLength () > 0)
|
||||||
|
m_ReceiveQueue.Put (packet);
|
||||||
|
else
|
||||||
|
delete packet;
|
||||||
|
m_LastReceivedSequenceNumber++;
|
||||||
|
SendQuickAck ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -90,13 +97,14 @@ namespace stream
|
||||||
m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); // pick another tunnel
|
m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); // pick another tunnel
|
||||||
if (m_OutboundTunnel)
|
if (m_OutboundTunnel)
|
||||||
SendQuickAck (); // resend ack for previous message again
|
SendQuickAck (); // resend ack for previous message again
|
||||||
|
delete packet; // packet dropped
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint ("Missing messages from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1);
|
LogPrint ("Missing messages from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1);
|
||||||
// actually do nothing. just wait for missing message again
|
// save message and wait for missing message again
|
||||||
|
SavePacket (packet);
|
||||||
}
|
}
|
||||||
delete packet; // packet dropped
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & PACKET_FLAG_CLOSE)
|
if (flags & PACKET_FLAG_CLOSE)
|
||||||
|
@ -107,6 +115,11 @@ namespace stream
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stream::SavePacket (Packet * packet)
|
||||||
|
{
|
||||||
|
m_SavedPackets.insert (packet);
|
||||||
|
}
|
||||||
|
|
||||||
size_t Stream::Send (uint8_t * buf, size_t len, int timeout)
|
size_t Stream::Send (uint8_t * buf, size_t len, int timeout)
|
||||||
{
|
{
|
||||||
if (!m_IsOpen)
|
if (!m_IsOpen)
|
||||||
|
|
24
Streaming.h
24
Streaming.h
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
#include <cryptopp/dsa.h>
|
#include <cryptopp/dsa.h>
|
||||||
|
#include "I2PEndian.h"
|
||||||
#include "Queue.h"
|
#include "Queue.h"
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "LeaseSet.h"
|
#include "LeaseSet.h"
|
||||||
|
@ -37,6 +39,25 @@ namespace stream
|
||||||
Packet (): len (0), offset (0) {};
|
Packet (): len (0), offset (0) {};
|
||||||
uint8_t * GetBuffer () { return buf + offset; };
|
uint8_t * GetBuffer () { return buf + offset; };
|
||||||
size_t GetLength () const { return len - offset; };
|
size_t GetLength () const { return len - offset; };
|
||||||
|
|
||||||
|
uint32_t GetSendStreamID () const { return be32toh (*(uint32_t *)buf); };
|
||||||
|
uint32_t GetReceiveStreamID () const { return be32toh (*(uint32_t *)(buf + 4)); };
|
||||||
|
uint32_t GetSeqn () const { return be32toh (*(uint32_t *)(buf + 8)); };
|
||||||
|
uint32_t GetAckThrough () const { return be32toh (*(uint32_t *)(buf + 12)); };
|
||||||
|
uint8_t GetNACKCount () const { return buf[16]; };
|
||||||
|
const uint8_t * GetOption () const { return buf + 17 + GetNACKCount ()*4 + 3; }; // 3 = resendDelay + flags
|
||||||
|
uint16_t GetFlags () const { return be16toh (*(uint16_t *)(GetOption () - 2)); };
|
||||||
|
uint16_t GetOptionSize () const { return be16toh (*(uint16_t *)GetOption ()); };
|
||||||
|
const uint8_t * GetOptionData () const { return GetOption () + 2; };
|
||||||
|
const uint8_t * GetPayload () const { return GetOptionData () + GetOptionSize (); };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PacketCmp
|
||||||
|
{
|
||||||
|
bool operator() (const Packet * p1, const Packet * p2) const
|
||||||
|
{
|
||||||
|
return p1->GetSeqn () < p2->GetSeqn ();
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class StreamingDestination;
|
class StreamingDestination;
|
||||||
|
@ -61,6 +82,8 @@ namespace stream
|
||||||
|
|
||||||
void ConnectAndSend (uint8_t * buf, size_t len);
|
void ConnectAndSend (uint8_t * buf, size_t len);
|
||||||
void SendQuickAck ();
|
void SendQuickAck ();
|
||||||
|
|
||||||
|
void SavePacket (Packet * packet);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -69,6 +92,7 @@ namespace stream
|
||||||
StreamingDestination * m_LocalDestination;
|
StreamingDestination * m_LocalDestination;
|
||||||
const i2p::data::LeaseSet * m_RemoteLeaseSet;
|
const i2p::data::LeaseSet * m_RemoteLeaseSet;
|
||||||
i2p::util::Queue<Packet> m_ReceiveQueue;
|
i2p::util::Queue<Packet> m_ReceiveQueue;
|
||||||
|
std::set<Packet *, PacketCmp> m_SavedPackets;
|
||||||
i2p::tunnel::OutboundTunnel * m_OutboundTunnel;
|
i2p::tunnel::OutboundTunnel * m_OutboundTunnel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -139,7 +156,7 @@ namespace i2p
|
||||||
auto address = r->GetNTCPAddress ();
|
auto address = r->GetNTCPAddress ();
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
session = new i2p::ntcp::NTCPClient (m_Service, address->host.c_str (), address->port, *r);
|
session = new i2p::ntcp::NTCPClient (m_Service, address->host, address->port, *r);
|
||||||
AddNTCPSession (session);
|
AddNTCPSession (session);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
14
Tunnel.cpp
14
Tunnel.cpp
|
@ -395,16 +395,16 @@ namespace tunnel
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//OutboundTunnel * outboundTunnel = GetNextOutboundTunnel ();
|
|
||||||
LogPrint ("Creating two hops outbound tunnel...");
|
LogPrint ("Creating two hops outbound tunnel...");
|
||||||
|
auto firstHop = i2p::data::netdb.GetRandomNTCPRouter (); // first hop must be NTCP
|
||||||
CreateTunnel<OutboundTunnel> (
|
CreateTunnel<OutboundTunnel> (
|
||||||
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
|
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
|
||||||
{
|
{
|
||||||
i2p::data::netdb.GetRandomNTCPRouter (),
|
firstHop,
|
||||||
i2p::data::netdb.GetRandomNTCPRouter ()
|
i2p::data::netdb.GetRandomRouter (firstHop)
|
||||||
},
|
},
|
||||||
inboundTunnel->GetTunnelConfig ())/*,
|
inboundTunnel->GetTunnelConfig ()));
|
||||||
outboundTunnel*/);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,8 +450,8 @@ namespace tunnel
|
||||||
CreateTunnel<InboundTunnel> (
|
CreateTunnel<InboundTunnel> (
|
||||||
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
|
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
|
||||||
{
|
{
|
||||||
i2p::data::netdb.GetRandomNTCPRouter (),
|
i2p::data::netdb.GetRandomRouter (outboundTunnel->GetEndpointRouter ()),
|
||||||
router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomNTCPRouter ()
|
router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomNTCPRouter () // last hop must be NTCP
|
||||||
}),
|
}),
|
||||||
outboundTunnel);
|
outboundTunnel);
|
||||||
}
|
}
|
||||||
|
|
3
Tunnel.h
3
Tunnel.h
|
@ -67,7 +67,8 @@ namespace tunnel
|
||||||
|
|
||||||
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg);
|
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg);
|
||||||
void SendTunnelDataMsg (std::vector<TunnelMessageBlock> msgs); // multiple messages
|
void SendTunnelDataMsg (std::vector<TunnelMessageBlock> msgs); // multiple messages
|
||||||
|
const i2p::data::RouterInfo * GetEndpointRouter () const
|
||||||
|
{ return GetTunnelConfig ()->GetLastHop ()->router; };
|
||||||
size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };
|
size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };
|
||||||
|
|
||||||
// implements TunnelBase
|
// implements TunnelBase
|
||||||
|
|
8
Win32/.gitignore
vendored
Normal file
8
Win32/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
*
|
||||||
|
!*/
|
||||||
|
|
||||||
|
!*.sln
|
||||||
|
!*.vcproj
|
||||||
|
!*.vcxproj
|
||||||
|
!*.vcxproj.filters
|
||||||
|
!.gitignore
|
|
@ -24,6 +24,7 @@
|
||||||
<ClCompile Include="..\NTCPSession.cpp" />
|
<ClCompile Include="..\NTCPSession.cpp" />
|
||||||
<ClCompile Include="..\RouterContext.cpp" />
|
<ClCompile Include="..\RouterContext.cpp" />
|
||||||
<ClCompile Include="..\RouterInfo.cpp" />
|
<ClCompile Include="..\RouterInfo.cpp" />
|
||||||
|
<ClCompile Include="..\SSU.cpp" />
|
||||||
<ClCompile Include="..\Streaming.cpp" />
|
<ClCompile Include="..\Streaming.cpp" />
|
||||||
<ClCompile Include="..\TransitTunnel.cpp" />
|
<ClCompile Include="..\TransitTunnel.cpp" />
|
||||||
<ClCompile Include="..\Transports.cpp" />
|
<ClCompile Include="..\Transports.cpp" />
|
||||||
|
@ -48,6 +49,7 @@
|
||||||
<ClInclude Include="..\Queue.h" />
|
<ClInclude Include="..\Queue.h" />
|
||||||
<ClInclude Include="..\RouterContext.h" />
|
<ClInclude Include="..\RouterContext.h" />
|
||||||
<ClInclude Include="..\RouterInfo.h" />
|
<ClInclude Include="..\RouterInfo.h" />
|
||||||
|
<ClInclude Include="..\SSU.h" />
|
||||||
<ClInclude Include="..\Streaming.h" />
|
<ClInclude Include="..\Streaming.h" />
|
||||||
<ClInclude Include="..\Timestamp.h" />
|
<ClInclude Include="..\Timestamp.h" />
|
||||||
<ClInclude Include="..\TransitTunnel.h" />
|
<ClInclude Include="..\TransitTunnel.h" />
|
||||||
|
|
|
@ -72,6 +72,9 @@
|
||||||
<ClCompile Include="..\I2PEndian.cpp">
|
<ClCompile Include="..\I2PEndian.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\SSU.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\Identity.h">
|
<ClInclude Include="..\Identity.h">
|
||||||
|
@ -149,5 +152,8 @@
|
||||||
<ClInclude Include="..\I2PEndian.h">
|
<ClInclude Include="..\I2PEndian.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\SSU.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -27,6 +27,11 @@ namespace data
|
||||||
'4', '5', '6', '7', '8', '9', '-', '~'
|
'4', '5', '6', '7', '8', '9', '-', '~'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char * GetBase64SubstitutionTable ()
|
||||||
|
{
|
||||||
|
return T64;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reverse Substitution Table (built in run time)
|
* Reverse Substitution Table (built in run time)
|
||||||
*/
|
*/
|
||||||
|
|
4
base64.h
4
base64.h
|
@ -11,9 +11,9 @@ namespace data
|
||||||
|
|
||||||
size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len);
|
size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len);
|
||||||
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
|
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
|
||||||
|
const char * GetBase64SubstitutionTable ();
|
||||||
|
|
||||||
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
|
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
59
hmac.h
Normal file
59
hmac.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#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[2048];
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
15
i2p.cpp
15
i2p.cpp
|
@ -10,10 +10,21 @@
|
||||||
#include "Tunnel.h"
|
#include "Tunnel.h"
|
||||||
#include "NetDb.h"
|
#include "NetDb.h"
|
||||||
#include "HTTPServer.h"
|
#include "HTTPServer.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
int main( int, char** )
|
int main( int argc, char* argv[] )
|
||||||
{
|
{
|
||||||
i2p::util::HTTPServer httpServer (7070);
|
i2p::util::ParseArguments(argc,argv);
|
||||||
|
#ifdef _WIN32
|
||||||
|
setlocale(LC_CTYPE, "");
|
||||||
|
SetConsoleCP(1251);
|
||||||
|
SetConsoleOutputCP(1251);
|
||||||
|
setlocale(LC_ALL, "Russian");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int httpport = i2p::util::GetIntArg("--httpport", 7070);
|
||||||
|
|
||||||
|
i2p::util::HTTPServer httpServer (httpport);
|
||||||
|
|
||||||
httpServer.Start ();
|
httpServer.Start ();
|
||||||
i2p::data::netdb.Start ();
|
i2p::data::netdb.Start ();
|
||||||
|
|
115
portable_endian.h
Normal file
115
portable_endian.h
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#ifndef PORTABLE_ENDIAN_H__
|
||||||
|
#define PORTABLE_ENDIAN_H__
|
||||||
|
|
||||||
|
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
|
||||||
|
|
||||||
|
# define __WINDOWS__
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__CYGWIN__)
|
||||||
|
|
||||||
|
# include <endian.h>
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
|
||||||
|
# include <libkern/OSByteOrder.h>
|
||||||
|
|
||||||
|
# define htobe16 OSSwapHostToBigInt16
|
||||||
|
# define htole16 OSSwapHostToLittleInt16
|
||||||
|
# define be16toh OSSwapBigToHostInt16
|
||||||
|
# define le16toh OSSwapLittleToHostInt16
|
||||||
|
|
||||||
|
# define htobe32 OSSwapHostToBigInt32
|
||||||
|
# define htole32 OSSwapHostToLittleInt32
|
||||||
|
# define be32toh OSSwapBigToHostInt32
|
||||||
|
# define le32toh OSSwapLittleToHostInt32
|
||||||
|
|
||||||
|
# define htobe64 OSSwapHostToBigInt64
|
||||||
|
# define htole64 OSSwapHostToLittleInt64
|
||||||
|
# define be64toh OSSwapBigToHostInt64
|
||||||
|
# define le64toh OSSwapLittleToHostInt64
|
||||||
|
|
||||||
|
# define __BYTE_ORDER BYTE_ORDER
|
||||||
|
# define __BIG_ENDIAN BIG_ENDIAN
|
||||||
|
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||||
|
# define __PDP_ENDIAN PDP_ENDIAN
|
||||||
|
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
|
||||||
|
# include <sys/endian.h>
|
||||||
|
|
||||||
|
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
|
|
||||||
|
# include <sys/endian.h>
|
||||||
|
|
||||||
|
# define be16toh betoh16
|
||||||
|
# define le16toh letoh16
|
||||||
|
|
||||||
|
# define be32toh betoh32
|
||||||
|
# define le32toh letoh32
|
||||||
|
|
||||||
|
# define be64toh betoh64
|
||||||
|
# define le64toh letoh64
|
||||||
|
|
||||||
|
#elif defined(__WINDOWS__)
|
||||||
|
|
||||||
|
#define INCL_EXTRA_HTON_FUNCTIONS
|
||||||
|
#define NOMINMAX
|
||||||
|
# include <winsock2.h>
|
||||||
|
#undef NOMINMAX
|
||||||
|
//# include <sys/param.h>
|
||||||
|
|
||||||
|
# if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
|
|
||||||
|
# define htobe16 htons
|
||||||
|
# define htole16(x) (x)
|
||||||
|
# define be16toh ntohs
|
||||||
|
# define le16toh(x) (x)
|
||||||
|
|
||||||
|
# define htobe32 htonl
|
||||||
|
# define htole32(x) (x)
|
||||||
|
# define be32toh ntohl
|
||||||
|
# define le32toh(x) (x)
|
||||||
|
|
||||||
|
# define htobe64 htonll
|
||||||
|
# define htole64(x) (x)
|
||||||
|
# define be64toh ntohll
|
||||||
|
# define le64toh(x) (x)
|
||||||
|
|
||||||
|
# elif BYTE_ORDER == BIG_ENDIAN
|
||||||
|
|
||||||
|
/* that would be xbox 360 */
|
||||||
|
# define htobe16(x) (x)
|
||||||
|
# define htole16(x) __builtin_bswap16(x)
|
||||||
|
# define be16toh(x) (x)
|
||||||
|
# define le16toh(x) __builtin_bswap16(x)
|
||||||
|
|
||||||
|
# define htobe32(x) (x)
|
||||||
|
# define htole32(x) __builtin_bswap32(x)
|
||||||
|
# define be32toh(x) (x)
|
||||||
|
# define le32toh(x) __builtin_bswap32(x)
|
||||||
|
|
||||||
|
# define htobe64(x) (x)
|
||||||
|
# define htole64(x) __builtin_bswap64(x)
|
||||||
|
# define be64toh(x) (x)
|
||||||
|
# define le64toh(x) __builtin_bswap64(x)
|
||||||
|
|
||||||
|
# else
|
||||||
|
|
||||||
|
# error byte order not supported
|
||||||
|
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# define __BYTE_ORDER BYTE_ORDER
|
||||||
|
# define __BIG_ENDIAN BIG_ENDIAN
|
||||||
|
# define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||||
|
# define __PDP_ENDIAN PDP_ENDIAN
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
# error platform not supported
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
45
util.cpp
Normal file
45
util.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string> mapArgs;
|
||||||
|
|
||||||
|
void ParseArguments(int argc, const char* const argv[])
|
||||||
|
{
|
||||||
|
mapArgs.clear();
|
||||||
|
for (int i = 1; i < argc; i++)
|
||||||
|
{
|
||||||
|
std::string strKey (argv[i]);
|
||||||
|
std::string strValue;
|
||||||
|
size_t has_data = strKey.find('=');
|
||||||
|
if (has_data != std::string::npos)
|
||||||
|
{
|
||||||
|
strValue = strKey.substr(has_data+1);
|
||||||
|
strKey = strKey.substr(0, has_data);
|
||||||
|
}
|
||||||
|
if (strKey[0] != '-')
|
||||||
|
break;
|
||||||
|
|
||||||
|
mapArgs[strKey] = strValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetIntArg(const std::string& strArg, int nDefault)
|
||||||
|
{
|
||||||
|
if (mapArgs.count(strArg))
|
||||||
|
return atoi(mapArgs[strArg].c_str());
|
||||||
|
return nDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetStringArg(const std::string& strArg, std::string nDefault)
|
||||||
|
{
|
||||||
|
if (mapArgs.count(strArg))
|
||||||
|
return mapArgs[strArg];
|
||||||
|
return nDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // Namespace end
|
||||||
|
}
|
19
util.h
Normal file
19
util.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef UTIL_H
|
||||||
|
#define UTIL_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace util
|
||||||
|
{
|
||||||
|
extern std::map<std::string, std::string> mapArgs;
|
||||||
|
void ParseArguments(int argc, const char* const argv[]);
|
||||||
|
int GetIntArg(const std::string& strArg, int nDefault);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Reference in a new issue