mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-04-24 01:46:36 +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
|
||||
#################
|
||||
|
|
|
@ -236,8 +236,8 @@ namespace garlic
|
|||
auto it = m_Sessions.find (destination->GetIdentHash ());
|
||||
if (it != m_Sessions.end ())
|
||||
{
|
||||
m_Sessions.erase (it);
|
||||
delete it->second;
|
||||
m_Sessions.erase (it);
|
||||
}
|
||||
GarlicRoutingSession * session = new GarlicRoutingSession (destination, 0); // not follow-on messages expected
|
||||
m_Sessions[destination->GetIdentHash ()] = session;
|
||||
|
|
|
@ -386,15 +386,13 @@ namespace i2p
|
|||
TunnelGatewayHeader * header = (TunnelGatewayHeader *)msg->GetPayload ();
|
||||
uint32_t tunnelID = be32toh(header->tunnelID);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("Tunnel ", (unsigned int)tunnelID, " not found");
|
||||
|
|
162
I2PEndian.cpp
162
I2PEndian.cpp
|
@ -1,81 +1,81 @@
|
|||
#include "I2PEndian.h"
|
||||
|
||||
// http://habrahabr.ru/post/121811/
|
||||
// http://codepad.org/2ycmkz2y
|
||||
|
||||
#include "LittleBigEndian.h"
|
||||
|
||||
uint16_t htobe16(uint16_t int16)
|
||||
{
|
||||
BigEndian<uint16_t> u16(int16);
|
||||
return u16.raw_value;
|
||||
}
|
||||
|
||||
uint32_t htobe32(uint32_t int32)
|
||||
{
|
||||
BigEndian<uint32_t> u32(int32);
|
||||
return u32.raw_value;
|
||||
}
|
||||
|
||||
uint64_t htobe64(uint64_t int64)
|
||||
{
|
||||
BigEndian<uint64_t> u64(int64);
|
||||
return u64.raw_value;
|
||||
}
|
||||
|
||||
uint16_t be16toh(uint16_t big16)
|
||||
{
|
||||
LittleEndian<uint16_t> u16(big16);
|
||||
return u16.raw_value;
|
||||
}
|
||||
|
||||
uint32_t be32toh(uint32_t big32)
|
||||
{
|
||||
LittleEndian<uint32_t> u32(big32);
|
||||
return u32.raw_value;
|
||||
}
|
||||
|
||||
uint64_t be64toh(uint64_t big64)
|
||||
{
|
||||
LittleEndian<uint64_t> u64(big64);
|
||||
return u64.raw_value;
|
||||
}
|
||||
|
||||
/* it can be used in Windows 8
|
||||
#include <Winsock2.h>
|
||||
|
||||
uint16_t htobe16(uint16_t int16)
|
||||
{
|
||||
return htons(int16);
|
||||
}
|
||||
|
||||
uint32_t htobe32(uint32_t int32)
|
||||
{
|
||||
return htonl(int32);
|
||||
}
|
||||
|
||||
uint64_t htobe64(uint64_t int64)
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
||||
//return htonll(int64);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint16_t be16toh(uint16_t big16)
|
||||
{
|
||||
return ntohs(big16);
|
||||
}
|
||||
|
||||
uint32_t be32toh(uint32_t big32)
|
||||
{
|
||||
return ntohl(big32);
|
||||
}
|
||||
|
||||
uint64_t be64toh(uint64_t big64)
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
||||
//return ntohll(big64);
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
//#include "I2PEndian.h"
|
||||
//
|
||||
//// http://habrahabr.ru/post/121811/
|
||||
//// http://codepad.org/2ycmkz2y
|
||||
//
|
||||
//#include "LittleBigEndian.h"
|
||||
//
|
||||
//uint16_t htobe16(uint16_t int16)
|
||||
//{
|
||||
// BigEndian<uint16_t> u16(int16);
|
||||
// return u16.raw_value;
|
||||
//}
|
||||
//
|
||||
//uint32_t htobe32(uint32_t int32)
|
||||
//{
|
||||
// BigEndian<uint32_t> u32(int32);
|
||||
// return u32.raw_value;
|
||||
//}
|
||||
//
|
||||
//uint64_t htobe64(uint64_t int64)
|
||||
//{
|
||||
// BigEndian<uint64_t> u64(int64);
|
||||
// return u64.raw_value;
|
||||
//}
|
||||
//
|
||||
//uint16_t be16toh(uint16_t big16)
|
||||
//{
|
||||
// LittleEndian<uint16_t> u16(big16);
|
||||
// return u16.raw_value;
|
||||
//}
|
||||
//
|
||||
//uint32_t be32toh(uint32_t big32)
|
||||
//{
|
||||
// LittleEndian<uint32_t> u32(big32);
|
||||
// return u32.raw_value;
|
||||
//}
|
||||
//
|
||||
//uint64_t be64toh(uint64_t big64)
|
||||
//{
|
||||
// LittleEndian<uint64_t> u64(big64);
|
||||
// return u64.raw_value;
|
||||
//}
|
||||
//
|
||||
///* it can be used in Windows 8
|
||||
//#include <Winsock2.h>
|
||||
//
|
||||
//uint16_t htobe16(uint16_t int16)
|
||||
//{
|
||||
// return htons(int16);
|
||||
//}
|
||||
//
|
||||
//uint32_t htobe32(uint32_t int32)
|
||||
//{
|
||||
// return htonl(int32);
|
||||
//}
|
||||
//
|
||||
//uint64_t htobe64(uint64_t int64)
|
||||
//{
|
||||
// // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
||||
// //return htonll(int64);
|
||||
// return 0;
|
||||
//}
|
||||
//
|
||||
//
|
||||
//uint16_t be16toh(uint16_t big16)
|
||||
//{
|
||||
// return ntohs(big16);
|
||||
//}
|
||||
//
|
||||
//uint32_t be32toh(uint32_t big32)
|
||||
//{
|
||||
// return ntohl(big32);
|
||||
//}
|
||||
//
|
||||
//uint64_t be64toh(uint64_t big64)
|
||||
//{
|
||||
// // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
||||
// //return ntohll(big64);
|
||||
// return 0;
|
||||
//}
|
||||
//*/
|
16
I2PEndian.h
16
I2PEndian.h
|
@ -5,14 +5,16 @@
|
|||
#include <endian.h>
|
||||
#else
|
||||
#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);
|
||||
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);
|
||||
#include "portable_endian.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
|
12
LeaseSet.cpp
12
LeaseSet.cpp
|
@ -3,6 +3,7 @@
|
|||
#include "CryptoConst.h"
|
||||
#include "Log.h"
|
||||
#include "Timestamp.h"
|
||||
#include "NetDb.h"
|
||||
#include "LeaseSet.h"
|
||||
|
||||
namespace i2p
|
||||
|
@ -28,6 +29,7 @@ namespace data
|
|||
memcpy (m_EncryptionKey, header->encryptionKey, 256);
|
||||
LogPrint ("LeaseSet num=", (int)header->num);
|
||||
|
||||
// process leases
|
||||
const uint8_t * leases = buf + sizeof (H);
|
||||
for (int i = 0; i < header->num; i++)
|
||||
{
|
||||
|
@ -36,8 +38,16 @@ namespace data
|
|||
lease.endDate = be64toh (lease.endDate);
|
||||
m_Leases.push_back (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
|
||||
CryptoPP::DSA::PublicKey pubKey;
|
||||
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
|
||||
OBJECTS = i2p.o base64.o NTCPSession.o RouterInfo.o Transports.o RouterContext.o \
|
||||
NetDb.o LeaseSet.o Tunnel.o TunnelEndpoint.o TunnelGateway.o TransitTunnel.o \
|
||||
I2NPProtocol.o Log.o Garlic.o HTTPServer.o Streaming.o Identity.o
|
||||
I2NPProtocol.o Log.o Garlic.o HTTPServer.o Streaming.o Identity.o SSU.o util.o
|
||||
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 =
|
||||
|
||||
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):
|
||||
NTCPSession (service, in_RouterInfo),
|
||||
m_Endpoint (boost::asio::ip::address::from_string (address), port)
|
||||
m_Endpoint (address, port)
|
||||
{
|
||||
Connect ();
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ namespace ntcp
|
|||
{
|
||||
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:
|
||||
|
||||
|
|
252
NetDb.cpp
252
NetDb.cpp
|
@ -1,6 +1,7 @@
|
|||
#include "I2PEndian.h"
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <cryptopp/gzip.h>
|
||||
#include "base64.h"
|
||||
|
@ -8,6 +9,7 @@
|
|||
#include "Timestamp.h"
|
||||
#include "I2NPProtocol.h"
|
||||
#include "Tunnel.h"
|
||||
#include "Transports.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Garlic.h"
|
||||
#include "NetDb.h"
|
||||
|
@ -29,6 +31,16 @@ namespace data
|
|||
m_LastReplyTunnel = replyTunnel;
|
||||
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;
|
||||
|
||||
|
@ -165,63 +177,106 @@ namespace data
|
|||
return it->second;
|
||||
else
|
||||
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)
|
||||
{
|
||||
boost::filesystem::path p (directory);
|
||||
if (boost::filesystem::exists (p))
|
||||
if (!boost::filesystem::exists (p))
|
||||
{
|
||||
int numRouters = 0;
|
||||
boost::filesystem::directory_iterator end;
|
||||
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
|
||||
if (!CreateNetDb(directory)) return;
|
||||
}
|
||||
// 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
|
||||
RouterInfo * r = new RouterInfo (it1->path().string().c_str ());
|
||||
RouterInfo * r = new RouterInfo (it1->path().string().c_str ());
|
||||
#else
|
||||
RouterInfo * r = new RouterInfo(it1->path().c_str());
|
||||
RouterInfo * r = new RouterInfo(it1->path().c_str());
|
||||
#endif
|
||||
m_RouterInfos[r->GetIdentHash ()] = r;
|
||||
numRouters++;
|
||||
}
|
||||
m_RouterInfos[r->GetIdentHash ()] = r;
|
||||
numRouters++;
|
||||
}
|
||||
}
|
||||
LogPrint (numRouters, " routers loaded");
|
||||
}
|
||||
else
|
||||
LogPrint (directory, " doesn't exist");
|
||||
LogPrint (numRouters, " routers loaded");
|
||||
}
|
||||
|
||||
void NetDb::SaveUpdated (const char * directory)
|
||||
{
|
||||
auto GetFilePath = [](const char * directory, const RouterInfo * routerInfo)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
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";
|
||||
};
|
||||
|
||||
int count = 0, deletedCount = 0;
|
||||
auto total = m_RouterInfos.size ();
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
for (auto it: m_RouterInfos)
|
||||
{
|
||||
if (it.second->IsUpdated ())
|
||||
{
|
||||
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 ());
|
||||
it.second->SetUpdated (false);
|
||||
count++;
|
||||
}
|
||||
else if (it.second->IsUnreachable ())
|
||||
else
|
||||
{
|
||||
if (boost::filesystem::exists (GetFilePath (directory, it.second)))
|
||||
{
|
||||
boost::filesystem::remove (GetFilePath (directory, it.second));
|
||||
deletedCount++;
|
||||
// RouterInfo expires in 72 hours if more than 300
|
||||
if (total > 300 && ts > it.second->GetTimestamp () + 3*24*3600*1000LL) // 3 days
|
||||
{
|
||||
total--;
|
||||
it.second->SetUnreachable (true);
|
||||
}
|
||||
|
||||
if (it.second->IsUnreachable ())
|
||||
{
|
||||
if (boost::filesystem::exists (GetFilePath (directory, it.second)))
|
||||
{
|
||||
boost::filesystem::remove (GetFilePath (directory, it.second));
|
||||
deletedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count > 0)
|
||||
|
@ -239,32 +294,49 @@ namespace data
|
|||
|
||||
void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet)
|
||||
{
|
||||
auto floodfill= GetRandomNTCPRouter (true);
|
||||
if (floodfill)
|
||||
RequestDestination (destination, floodfill, isLeaseSet);
|
||||
else
|
||||
LogPrint ("No floodfill routers found");
|
||||
}
|
||||
|
||||
void NetDb::RequestDestination (const IdentHash& destination, const RouterInfo * floodfill, bool isLeaseSet)
|
||||
{
|
||||
if (!floodfill) return;
|
||||
i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel ();
|
||||
if (outbound)
|
||||
{
|
||||
i2p::tunnel::InboundTunnel * inbound = i2p::tunnel::tunnels.GetNextInboundTunnel ();
|
||||
if (inbound)
|
||||
if (isLeaseSet) // we request LeaseSet through tunnels
|
||||
{
|
||||
i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel ();
|
||||
if (outbound)
|
||||
{
|
||||
RequestedDestination * dest = CreateRequestedDestination (destination, isLeaseSet);
|
||||
dest->SetLastOutboundTunnel (outbound);
|
||||
auto msg = dest->CreateRequestMessage (floodfill, inbound);
|
||||
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg);
|
||||
}
|
||||
i2p::tunnel::InboundTunnel * inbound = i2p::tunnel::tunnels.GetNextInboundTunnel ();
|
||||
if (inbound)
|
||||
{
|
||||
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
|
||||
LogPrint ("No inbound tunnels found");
|
||||
}
|
||||
else
|
||||
LogPrint ("No outbound tunnels found");
|
||||
LogPrint ("No outbound tunnels found");
|
||||
}
|
||||
else // RouterInfo is requested directly
|
||||
{
|
||||
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)
|
||||
|
@ -377,18 +449,25 @@ namespace data
|
|||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no more requests for detination possible. delete it
|
||||
m_RequestedDestinations.erase (it);
|
||||
delete it->second;
|
||||
m_RequestedDestinations.erase (it);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -402,7 +481,7 @@ namespace data
|
|||
auto inbound = i2p::tunnel::tunnels.GetNextInboundTunnel ();
|
||||
if (outbound && inbound)
|
||||
{
|
||||
auto floodfill = GetRandomNTCPRouter (true);
|
||||
auto floodfill = GetRandomRouter (outbound->GetEndpointRouter (), true);
|
||||
if (floodfill)
|
||||
{
|
||||
LogPrint ("Exploring new routers ...");
|
||||
|
@ -449,8 +528,8 @@ namespace data
|
|||
auto it = m_RequestedDestinations.find (dest);
|
||||
if (it != m_RequestedDestinations.end ())
|
||||
{
|
||||
m_RequestedDestinations.erase (it);
|
||||
delete it->second;
|
||||
m_RequestedDestinations.erase (it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -470,16 +549,29 @@ namespace data
|
|||
return last;
|
||||
}
|
||||
|
||||
const RouterInfo * NetDb::GetRandomRouter () const
|
||||
const RouterInfo * NetDb::GetRandomRouter (const RouterInfo * compatibleWith, bool floodfillOnly) const
|
||||
{
|
||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||
uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1), i = 0;
|
||||
for (auto it: m_RouterInfos)
|
||||
uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1);
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
if (i >= ind) return it.second;
|
||||
else i++;
|
||||
uint32_t i = 0;
|
||||
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)
|
||||
|
@ -487,7 +579,8 @@ namespace data
|
|||
if (msg) m_Queue.Put (msg);
|
||||
}
|
||||
|
||||
const RouterInfo * NetDb::GetClosestFloodfill (const IdentHash& destination) const
|
||||
const RouterInfo * NetDb::GetClosestFloodfill (const IdentHash& destination,
|
||||
const std::set<IdentHash>& excluded) const
|
||||
{
|
||||
RouterInfo * r = nullptr;
|
||||
XORMetric minMetric;
|
||||
|
@ -495,7 +588,7 @@ namespace data
|
|||
minMetric.SetMax ();
|
||||
for (auto it: m_RouterInfos)
|
||||
{
|
||||
if (it.second->IsFloodfill () &&! it.second->IsUnreachable ())
|
||||
if (it.second->IsFloodfill () &&! it.second->IsUnreachable () && !excluded.count (it.first))
|
||||
{
|
||||
XORMetric m = destKey ^ it.second->GetRoutingKey ();
|
||||
if (m < minMetric)
|
||||
|
@ -507,5 +600,46 @@ namespace data
|
|||
}
|
||||
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; };
|
||||
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; };
|
||||
bool IsExploratory () const { return m_IsExploratory; };
|
||||
bool IsLeaseSet () const { return m_IsLeaseSet; };
|
||||
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
|
||||
I2NPMessage * CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel);
|
||||
|
||||
I2NPMessage * CreateRequestMessage (const IdentHash& floodfill);
|
||||
|
||||
i2p::tunnel::OutboundTunnel * GetLastOutboundTunnel () const { return m_LastOutboundTunnel; };
|
||||
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 IdentHash& destination, bool isLeaseSet = false);
|
||||
void RequestDestination (const IdentHash& destination, const RouterInfo * floodfill, bool isLeaseSet = false);
|
||||
|
||||
|
||||
void HandleDatabaseStoreMsg (uint8_t * buf, size_t len);
|
||||
void HandleDatabaseSearchReplyMsg (I2NPMessage * msg);
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
|
||||
bool CreateNetDb(const char * directory);
|
||||
void Load (const char * directory);
|
||||
void SaveUpdated (const char * directory);
|
||||
void DownloadRouterInfo (const std::string& address, const std::string& filename); // for reseed
|
||||
void Run (); // exploratory thread
|
||||
void Explore ();
|
||||
const RouterInfo * GetClosestFloodfill (const IdentHash& destination) const;
|
||||
const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||
|
||||
RequestedDestination * CreateRequestedDestination (const IdentHash& dest,
|
||||
bool isLeaseSet, bool isExploratory = false);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <cryptopp/dsa.h>
|
||||
#include "CryptoConst.h"
|
||||
#include "RouterContext.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -45,7 +46,7 @@ namespace i2p
|
|||
auto address = m_RouterInfo.GetNTCPAddress ();
|
||||
if (address)
|
||||
{
|
||||
address->host = host;
|
||||
address->host = boost::asio::ip::address::from_string (host);
|
||||
address->port = port;
|
||||
}
|
||||
|
||||
|
@ -60,7 +61,7 @@ namespace i2p
|
|||
|
||||
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;
|
||||
|
||||
fk.read ((char *)&m_Keys, sizeof (m_Keys));
|
||||
|
@ -74,10 +75,10 @@ namespace i2p
|
|||
|
||||
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));
|
||||
|
||||
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 ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,18 +12,19 @@
|
|||
#include "RouterInfo.h"
|
||||
#include "RouterContext.h"
|
||||
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
RouterInfo::RouterInfo (const char * filename):
|
||||
m_IsUpdated (false), m_IsUnreachable (false)
|
||||
m_IsUpdated (false), m_IsUnreachable (false), m_SupportedTransports (0)
|
||||
{
|
||||
ReadFromFile (filename);
|
||||
}
|
||||
|
||||
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);
|
||||
m_BufferLen = len;
|
||||
|
@ -41,7 +42,7 @@ namespace data
|
|||
|
||||
void RouterInfo::ReadFromFile (const char * filename)
|
||||
{
|
||||
std::ifstream s(filename);
|
||||
std::ifstream s(filename, std::ifstream::binary);
|
||||
if (s.is_open ())
|
||||
{
|
||||
s.seekg (0,std::ios::end);
|
||||
|
@ -95,15 +96,34 @@ namespace data
|
|||
size = be16toh (size);
|
||||
while (r < size)
|
||||
{
|
||||
char key[50], value[50];
|
||||
char key[500], value[500];
|
||||
r += ReadString (key, s);
|
||||
s.seekg (1, std::ios_base::cur); r++; // =
|
||||
r += ReadString (value, s);
|
||||
s.seekg (1, std::ios_base::cur); r++; // ;
|
||||
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"))
|
||||
address.port = boost::lexical_cast<int>(value);
|
||||
else if (!strcmp (key, "key"))
|
||||
Base64ToByteStream (value, strlen (value), address.key, 32);
|
||||
}
|
||||
m_Addresses.push_back(address);
|
||||
}
|
||||
|
@ -117,7 +137,13 @@ namespace data
|
|||
size = be16toh (size);
|
||||
while (r < size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
char key[500], value[500];
|
||||
// TODO: investigate why properties get read as one long string under Windows
|
||||
// length should not be more than 44
|
||||
#else
|
||||
char key[50], value[50];
|
||||
#endif
|
||||
r += ReadString (key, s);
|
||||
s.seekg (1, std::ios_base::cur); r++; // =
|
||||
r += ReadString (value, s);
|
||||
|
@ -166,7 +192,7 @@ namespace data
|
|||
std::stringstream properties;
|
||||
WriteString ("host", properties);
|
||||
properties << '=';
|
||||
WriteString (address.host, properties);
|
||||
WriteString (address.host.to_string (), properties);
|
||||
properties << ';';
|
||||
WriteString ("port", properties);
|
||||
properties << '=';
|
||||
|
@ -227,7 +253,7 @@ namespace data
|
|||
void RouterInfo::AddNTCPAddress (const char * host, int port)
|
||||
{
|
||||
Address addr;
|
||||
addr.host = host;
|
||||
addr.host = boost::asio::ip::address::from_string (host);
|
||||
addr.port = port;
|
||||
addr.transportStyle = eTransportNTCP;
|
||||
addr.cost = 2;
|
||||
|
@ -256,22 +282,33 @@ namespace data
|
|||
return false;
|
||||
}
|
||||
|
||||
bool RouterInfo::IsNTCP () const
|
||||
bool RouterInfo::IsNTCP (bool v4only) const
|
||||
{
|
||||
for (auto& address : m_Addresses)
|
||||
{
|
||||
if (address.transportStyle == eTransportNTCP)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (v4only)
|
||||
return m_SupportedTransports & eNTCPV4;
|
||||
else
|
||||
return m_SupportedTransports & (eNTCPV4 | eNTCPV6);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (address.transportStyle == eTransportNTCP)
|
||||
return &address;
|
||||
if (address.transportStyle == s)
|
||||
{
|
||||
if (!v4only || address.host.is_v4 ())
|
||||
return &address;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
20
RouterInfo.h
20
RouterInfo.h
|
@ -17,6 +17,14 @@ namespace data
|
|||
{
|
||||
public:
|
||||
|
||||
enum SupportedTranports
|
||||
{
|
||||
eNTCPV4 = 0x01,
|
||||
eNTCPV6 = 0x20,
|
||||
eSSUV4 = 0x40,
|
||||
eSSUV6 = 0x80
|
||||
};
|
||||
|
||||
enum TransportStyle
|
||||
{
|
||||
eTransportUnknown = 0,
|
||||
|
@ -27,10 +35,11 @@ namespace data
|
|||
struct Address
|
||||
{
|
||||
TransportStyle transportStyle;
|
||||
std::string host;
|
||||
boost::asio::ip::address host;
|
||||
int port;
|
||||
uint64_t date;
|
||||
uint8_t cost;
|
||||
uint8_t key[32]; // into key for SSU
|
||||
};
|
||||
|
||||
RouterInfo (const char * filename);
|
||||
|
@ -45,14 +54,17 @@ namespace data
|
|||
const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; };
|
||||
uint64_t GetTimestamp () const { return m_Timestamp; };
|
||||
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; };
|
||||
|
||||
void AddNTCPAddress (const char * host, int port);
|
||||
void SetProperty (const char * key, const char * value);
|
||||
const char * GetProperty (const char * key) 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; };
|
||||
bool IsUnreachable () const { return m_IsUnreachable; };
|
||||
|
||||
|
@ -78,6 +90,7 @@ namespace data
|
|||
size_t ReadString (char * str, std::istream& s);
|
||||
void WriteString (const std::string& str, std::ostream& s);
|
||||
void UpdateIdentHashBase64 ();
|
||||
Address * GetAddress (TransportStyle s, bool v4only);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -91,6 +104,7 @@ namespace data
|
|||
std::vector<Address> m_Addresses;
|
||||
std::map<std::string, std::string> m_Properties;
|
||||
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 <algorithm>
|
||||
#include <cryptopp/gzip.h>
|
||||
|
@ -26,30 +25,18 @@ namespace stream
|
|||
{
|
||||
while (auto packet = m_ReceiveQueue.Get ())
|
||||
delete packet;
|
||||
for (auto it: m_SavedPackets)
|
||||
delete it;
|
||||
}
|
||||
|
||||
void Stream::HandleNextPacket (Packet * packet)
|
||||
{
|
||||
const uint8_t * buf = packet->buf;
|
||||
buf += 4; // sendStreamID
|
||||
if (!m_SendStreamID)
|
||||
m_SendStreamID = be32toh (*(uint32_t *)buf);
|
||||
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;
|
||||
|
||||
m_SendStreamID = packet->GetReceiveStreamID ();
|
||||
|
||||
// process flags
|
||||
uint16_t flags = packet->GetFlags ();
|
||||
const uint8_t * optionData = packet->GetOptionData ();
|
||||
if (flags & PACKET_FLAG_SYNCHRONIZE)
|
||||
{
|
||||
LogPrint ("Synchronize");
|
||||
|
@ -58,21 +45,21 @@ namespace stream
|
|||
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
||||
{
|
||||
LogPrint ("Signature");
|
||||
optionalData += 40;
|
||||
optionData += 40;
|
||||
}
|
||||
|
||||
if (flags & PACKET_FLAG_FROM_INCLUDED)
|
||||
{
|
||||
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);
|
||||
if (!receivedSeqn || receivedSeqn == m_LastReceivedSequenceNumber + 1)
|
||||
{
|
||||
// we have received next message
|
||||
packet->offset = buf - packet->buf;
|
||||
packet->offset = packet->GetPayload () - packet->buf;
|
||||
if (packet->GetLength () > 0)
|
||||
m_ReceiveQueue.Put (packet);
|
||||
else
|
||||
|
@ -80,6 +67,26 @@ namespace stream
|
|||
|
||||
m_LastReceivedSequenceNumber = receivedSeqn;
|
||||
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
|
||||
{
|
||||
|
@ -90,13 +97,14 @@ namespace stream
|
|||
m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); // pick another tunnel
|
||||
if (m_OutboundTunnel)
|
||||
SendQuickAck (); // resend ack for previous message again
|
||||
delete packet; // packet dropped
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
if (!m_IsOpen)
|
||||
|
|
24
Streaming.h
24
Streaming.h
|
@ -3,7 +3,9 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <cryptopp/dsa.h>
|
||||
#include "I2PEndian.h"
|
||||
#include "Queue.h"
|
||||
#include "Identity.h"
|
||||
#include "LeaseSet.h"
|
||||
|
@ -37,6 +39,25 @@ namespace stream
|
|||
Packet (): len (0), offset (0) {};
|
||||
uint8_t * GetBuffer () { return buf + 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;
|
||||
|
@ -61,6 +82,8 @@ namespace stream
|
|||
|
||||
void ConnectAndSend (uint8_t * buf, size_t len);
|
||||
void SendQuickAck ();
|
||||
|
||||
void SavePacket (Packet * packet);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -69,6 +92,7 @@ namespace stream
|
|||
StreamingDestination * m_LocalDestination;
|
||||
const i2p::data::LeaseSet * m_RemoteLeaseSet;
|
||||
i2p::util::Queue<Packet> m_ReceiveQueue;
|
||||
std::set<Packet *, PacketCmp> m_SavedPackets;
|
||||
i2p::tunnel::OutboundTunnel * m_OutboundTunnel;
|
||||
};
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace i2p
|
|||
Transports transports;
|
||||
|
||||
Transports::Transports ():
|
||||
m_Thread (0), m_Work (m_Service),m_NTCPAcceptor (0)
|
||||
m_Thread (nullptr), m_Work (m_Service),m_NTCPAcceptor (nullptr), m_SSUServer (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,11 +34,22 @@ namespace i2p
|
|||
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service,
|
||||
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port));
|
||||
|
||||
LogPrint ("Start listening port ", address.port);
|
||||
LogPrint ("Start listening TCP port ", address.port);
|
||||
auto conn = new i2p::ntcp::NTCPServerConnection (m_Service);
|
||||
m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this,
|
||||
conn, boost::asio::placeholders::error));
|
||||
}
|
||||
else if (address.transportStyle == RouterInfo::eTransportSSU)
|
||||
{
|
||||
if (!m_SSUServer)
|
||||
{
|
||||
m_SSUServer = new i2p::ssu::SSUServer (m_Service, address.port);
|
||||
LogPrint ("Start listening UDP port ", address.port);
|
||||
m_SSUServer->Start ();
|
||||
}
|
||||
else
|
||||
LogPrint ("SSU server already exists");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +60,12 @@ namespace i2p
|
|||
m_NTCPSessions.clear ();
|
||||
delete m_NTCPAcceptor;
|
||||
|
||||
if (m_SSUServer)
|
||||
{
|
||||
m_SSUServer->Stop ();
|
||||
delete m_SSUServer;
|
||||
}
|
||||
|
||||
m_IsRunning = false;
|
||||
m_Service.stop ();
|
||||
if (m_Thread)
|
||||
|
@ -139,7 +156,7 @@ namespace i2p
|
|||
auto address = r->GetNTCPAddress ();
|
||||
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);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
#include <boost/asio.hpp>
|
||||
#include "NTCPSession.h"
|
||||
#include "SSU.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "I2NPProtocol.h"
|
||||
|
||||
|
@ -47,6 +48,7 @@ namespace i2p
|
|||
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor;
|
||||
|
||||
std::map<i2p::data::IdentHash, i2p::ntcp::NTCPSession *> m_NTCPSessions;
|
||||
i2p::ssu::SSUServer * m_SSUServer;
|
||||
|
||||
public:
|
||||
|
||||
|
|
14
Tunnel.cpp
14
Tunnel.cpp
|
@ -395,16 +395,16 @@ namespace tunnel
|
|||
}
|
||||
else
|
||||
{
|
||||
//OutboundTunnel * outboundTunnel = GetNextOutboundTunnel ();
|
||||
|
||||
LogPrint ("Creating two hops outbound tunnel...");
|
||||
auto firstHop = i2p::data::netdb.GetRandomNTCPRouter (); // first hop must be NTCP
|
||||
CreateTunnel<OutboundTunnel> (
|
||||
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
|
||||
{
|
||||
i2p::data::netdb.GetRandomNTCPRouter (),
|
||||
i2p::data::netdb.GetRandomNTCPRouter ()
|
||||
firstHop,
|
||||
i2p::data::netdb.GetRandomRouter (firstHop)
|
||||
},
|
||||
inboundTunnel->GetTunnelConfig ())/*,
|
||||
outboundTunnel*/);
|
||||
inboundTunnel->GetTunnelConfig ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -450,8 +450,8 @@ namespace tunnel
|
|||
CreateTunnel<InboundTunnel> (
|
||||
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
|
||||
{
|
||||
i2p::data::netdb.GetRandomNTCPRouter (),
|
||||
router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomNTCPRouter ()
|
||||
i2p::data::netdb.GetRandomRouter (outboundTunnel->GetEndpointRouter ()),
|
||||
router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomNTCPRouter () // last hop must be NTCP
|
||||
}),
|
||||
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 (std::vector<TunnelMessageBlock> msgs); // multiple messages
|
||||
|
||||
const i2p::data::RouterInfo * GetEndpointRouter () const
|
||||
{ return GetTunnelConfig ()->GetLastHop ()->router; };
|
||||
size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };
|
||||
|
||||
// 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="..\RouterContext.cpp" />
|
||||
<ClCompile Include="..\RouterInfo.cpp" />
|
||||
<ClCompile Include="..\SSU.cpp" />
|
||||
<ClCompile Include="..\Streaming.cpp" />
|
||||
<ClCompile Include="..\TransitTunnel.cpp" />
|
||||
<ClCompile Include="..\Transports.cpp" />
|
||||
|
@ -48,6 +49,7 @@
|
|||
<ClInclude Include="..\Queue.h" />
|
||||
<ClInclude Include="..\RouterContext.h" />
|
||||
<ClInclude Include="..\RouterInfo.h" />
|
||||
<ClInclude Include="..\SSU.h" />
|
||||
<ClInclude Include="..\Streaming.h" />
|
||||
<ClInclude Include="..\Timestamp.h" />
|
||||
<ClInclude Include="..\TransitTunnel.h" />
|
||||
|
|
|
@ -72,6 +72,9 @@
|
|||
<ClCompile Include="..\I2PEndian.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\SSU.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Identity.h">
|
||||
|
@ -149,5 +152,8 @@
|
|||
<ClInclude Include="..\I2PEndian.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\SSU.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -27,6 +27,11 @@ namespace data
|
|||
'4', '5', '6', '7', '8', '9', '-', '~'
|
||||
};
|
||||
|
||||
const char * GetBase64SubstitutionTable ()
|
||||
{
|
||||
return T64;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
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 "NetDb.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 ();
|
||||
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