mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-04-23 17:36:37 +02:00
commit
0438fc77bd
32 changed files with 1276 additions and 416 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,5 +1,5 @@
|
||||||
# i2pd
|
# i2pd
|
||||||
*.o
|
obj/*.o
|
||||||
router.info
|
router.info
|
||||||
router.keys
|
router.keys
|
||||||
i2p
|
i2p
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "I2PEndian.h"
|
||||||
#include "RouterInfo.h"
|
#include "RouterInfo.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
|
@ -19,6 +20,12 @@ namespace i2p
|
||||||
uint8_t chks;
|
uint8_t chks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct I2NPHeaderShort
|
||||||
|
{
|
||||||
|
uint8_t typeID;
|
||||||
|
uint32_t shortExpiration;
|
||||||
|
};
|
||||||
|
|
||||||
struct I2NPDatabaseStoreMsg
|
struct I2NPDatabaseStoreMsg
|
||||||
{
|
{
|
||||||
uint8_t key[32];
|
uint8_t key[32];
|
||||||
|
@ -101,6 +108,19 @@ namespace i2p
|
||||||
len = offset + other.GetLength ();
|
len = offset + other.GetLength ();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for SSU only
|
||||||
|
uint8_t * GetSSUHeader () { return buf + offset + sizeof(I2NPHeader) - sizeof(I2NPHeaderShort); };
|
||||||
|
void FromSSU (uint32_t msgID) // we have received SSU message and convert it to regular
|
||||||
|
{
|
||||||
|
I2NPHeaderShort ssu = *(I2NPHeaderShort *)GetSSUHeader ();
|
||||||
|
I2NPHeader * header = GetHeader ();
|
||||||
|
header->typeID = ssu.typeID;
|
||||||
|
header->msgID = htobe32 (msgID);
|
||||||
|
header->expiration = htobe64 (be32toh (ssu.shortExpiration)*1000LL);
|
||||||
|
header->size = htobe16 (len - offset - sizeof (I2NPHeader));
|
||||||
|
header->chks = 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
I2NPMessage * NewI2NPMessage ();
|
I2NPMessage * NewI2NPMessage ();
|
||||||
void DeleteI2NPMessage (I2NPMessage * msg);
|
void DeleteI2NPMessage (I2NPMessage * msg);
|
||||||
|
|
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,16 +5,14 @@
|
||||||
#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);
|
|
||||||
|
|
||||||
#include "portable_endian.h"
|
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);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -57,13 +57,13 @@ namespace data
|
||||||
LogPrint ("LeaseSet verification failed");
|
LogPrint ("LeaseSet verification failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Lease> LeaseSet::GetNonExpiredLeases () const
|
std::set<Lease> LeaseSet::GetNonExpiredLeases () const
|
||||||
{
|
{
|
||||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
std::vector<Lease> leases;
|
std::set<Lease> leases;
|
||||||
for (auto& it: m_Leases)
|
for (auto& it: m_Leases)
|
||||||
if (ts < it.endDate)
|
if (ts < it.endDate)
|
||||||
leases.push_back (it);
|
leases.insert (it);
|
||||||
return leases;
|
return leases;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
LeaseSet.h
11
LeaseSet.h
|
@ -4,6 +4,7 @@
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
|
@ -18,6 +19,14 @@ namespace data
|
||||||
uint8_t tunnelGateway[32];
|
uint8_t tunnelGateway[32];
|
||||||
uint32_t tunnelID;
|
uint32_t tunnelID;
|
||||||
uint64_t endDate;
|
uint64_t endDate;
|
||||||
|
|
||||||
|
bool operator< (const Lease& other) const
|
||||||
|
{
|
||||||
|
if (endDate != other.endDate)
|
||||||
|
return endDate > other.endDate;
|
||||||
|
else
|
||||||
|
return tunnelID < other.tunnelID;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
@ -34,7 +43,7 @@ namespace data
|
||||||
const Identity& GetIdentity () const { return m_Identity; };
|
const Identity& GetIdentity () const { return m_Identity; };
|
||||||
const IdentHash& GetIdentHash () const { return m_IdentHash; };
|
const IdentHash& GetIdentHash () const { return m_IdentHash; };
|
||||||
const std::vector<Lease>& GetLeases () const { return m_Leases; };
|
const std::vector<Lease>& GetLeases () const { return m_Leases; };
|
||||||
std::vector<Lease> GetNonExpiredLeases () const;
|
std::set<Lease> GetNonExpiredLeases () const;
|
||||||
bool HasExpiredLeases () const;
|
bool HasExpiredLeases () const;
|
||||||
bool HasNonExpiredLeases () const;
|
bool HasNonExpiredLeases () const;
|
||||||
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; };
|
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; };
|
||||||
|
|
|
@ -59,12 +59,12 @@ struct LittleEndian
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
const T operator = (const T t)
|
const T operator = (const T t)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < sizeof(T); i++)
|
for (unsigned i = 0; i < sizeof(T); i++)
|
||||||
bytes[i] = t >> (i << 3);
|
bytes[sizeof(T)-1 - i] = static_cast<unsigned char>(t >> (i << 3));
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
// operators
|
// operators
|
||||||
|
|
||||||
|
|
25
Makefile
25
Makefile
|
@ -1,26 +1,31 @@
|
||||||
|
|
||||||
CC = g++
|
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 = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \
|
||||||
NetDb.o LeaseSet.o Tunnel.o TunnelEndpoint.o TunnelGateway.o TransitTunnel.o \
|
obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \
|
||||||
I2NPProtocol.o Log.o Garlic.o HTTPServer.o Streaming.o Identity.o SSU.o util.o
|
obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \
|
||||||
|
obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o
|
||||||
INCFLAGS =
|
INCFLAGS =
|
||||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lpthread
|
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||||
LIBS =
|
LIBS =
|
||||||
|
|
||||||
all: i2p
|
all: obj i2p
|
||||||
|
|
||||||
i2p: $(OBJECTS)
|
i2p: $(OBJECTS:obj/%=obj/%)
|
||||||
$(CC) -o i2p $(OBJECTS) $(LDFLAGS) $(LIBS)
|
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
|
||||||
|
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.SUFFIXES: .c .cc .C .cpp .o
|
.SUFFIXES: .c .cc .C .cpp .o
|
||||||
|
|
||||||
.cpp.o :
|
obj/%.o : %.cpp
|
||||||
$(CC) -o $@ -c $(CFLAGS) $< $(INCFLAGS)
|
$(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS)
|
||||||
|
|
||||||
|
obj:
|
||||||
|
mkdir -p obj
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o
|
rm -fr obj i2p
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
||||||
|
|
|
@ -474,7 +474,9 @@ namespace ntcp
|
||||||
if (ecode)
|
if (ecode)
|
||||||
{
|
{
|
||||||
LogPrint ("Couldn't send msg: ", ecode.message ());
|
LogPrint ("Couldn't send msg: ", ecode.message ());
|
||||||
Terminate ();
|
// we shouldn't call Terminate () here, because HandleReceive takes care
|
||||||
|
// TODO: 'delete this' statement in Terminate () must be eliminated later
|
||||||
|
// Terminate ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
107
NetDb.cpp
107
NetDb.cpp
|
@ -2,7 +2,6 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <cryptopp/gzip.h>
|
#include <cryptopp/gzip.h>
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
@ -13,12 +12,13 @@
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
#include "Garlic.h"
|
#include "Garlic.h"
|
||||||
#include "NetDb.h"
|
#include "NetDb.h"
|
||||||
|
#include "Reseed.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace data
|
namespace data
|
||||||
{
|
{
|
||||||
|
|
||||||
I2NPMessage * RequestedDestination::CreateRequestMessage (const RouterInfo * router,
|
I2NPMessage * RequestedDestination::CreateRequestMessage (const RouterInfo * router,
|
||||||
const i2p::tunnel::InboundTunnel * replyTunnel)
|
const i2p::tunnel::InboundTunnel * replyTunnel)
|
||||||
{
|
{
|
||||||
|
@ -41,10 +41,15 @@ namespace data
|
||||||
m_LastReplyTunnel = nullptr;
|
m_LastReplyTunnel = nullptr;
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
const char NetDb::m_NetDbPath[] = "/netDb";
|
||||||
|
#else
|
||||||
|
const char NetDb::m_NetDbPath[] = "\\netDb";
|
||||||
|
#endif
|
||||||
NetDb netdb;
|
NetDb netdb;
|
||||||
|
|
||||||
NetDb::NetDb (): m_IsRunning (false), m_Thread (0)
|
NetDb::NetDb (): m_IsRunning (false), m_ReseedRetries (0), m_Thread (0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,8 +65,15 @@ namespace data
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::Start ()
|
void NetDb::Start ()
|
||||||
{
|
{
|
||||||
Load ("netDb");
|
Load (m_NetDbPath);
|
||||||
|
while (m_RouterInfos.size () < 100 && m_ReseedRetries < 10)
|
||||||
|
{
|
||||||
|
Reseeder reseeder;
|
||||||
|
reseeder.reseedNow();
|
||||||
|
m_ReseedRetries++;
|
||||||
|
Load (m_NetDbPath);
|
||||||
|
}
|
||||||
m_Thread = new std::thread (std::bind (&NetDb::Run, this));
|
m_Thread = new std::thread (std::bind (&NetDb::Run, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +123,7 @@ namespace data
|
||||||
if (ts - lastTs >= 60) // save routers every minute
|
if (ts - lastTs >= 60) // save routers every minute
|
||||||
{
|
{
|
||||||
if (lastTs)
|
if (lastTs)
|
||||||
SaveUpdated ("netDb");
|
SaveUpdated (m_NetDbPath);
|
||||||
lastTs = ts;
|
lastTs = ts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,13 +192,12 @@ namespace data
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move to reseed and/or scheduled tasks. (In java version, scheduler fix this as well as sort RIs.)
|
// 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)
|
bool NetDb::CreateNetDb(boost::filesystem::path directory)
|
||||||
{
|
{
|
||||||
boost::filesystem::path p (directory);
|
LogPrint (directory.string(), " doesn't exist, trying to create it.");
|
||||||
LogPrint (directory, " doesn't exist, trying to create it.");
|
if (!boost::filesystem::create_directory (directory))
|
||||||
if (!boost::filesystem::create_directory (p))
|
|
||||||
{
|
{
|
||||||
LogPrint("Failed to create directory ", directory);
|
LogPrint("Failed to create directory ", directory.string());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,19 +211,26 @@ namespace data
|
||||||
#else
|
#else
|
||||||
suffix = std::string ("\\r") + chars[i];
|
suffix = std::string ("\\r") + chars[i];
|
||||||
#endif
|
#endif
|
||||||
if (!boost::filesystem::create_directory( boost::filesystem::path (p / suffix) )) return false;
|
if (!boost::filesystem::create_directory( boost::filesystem::path (directory / suffix) )) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetDb::Load (const char * directory)
|
void NetDb::Load (const char * directory)
|
||||||
{
|
{
|
||||||
boost::filesystem::path p (directory);
|
boost::filesystem::path p (i2p::util::filesystem::GetDataDir());
|
||||||
|
p /= (directory);
|
||||||
if (!boost::filesystem::exists (p))
|
if (!boost::filesystem::exists (p))
|
||||||
{
|
{
|
||||||
if (!CreateNetDb(directory)) return;
|
// seems netDb doesn't exist yet
|
||||||
|
if (!CreateNetDb(p)) return;
|
||||||
}
|
}
|
||||||
// TODO: Reseed if needed.
|
// make sure we cleanup netDb from previous attempts
|
||||||
|
for (auto r: m_RouterInfos)
|
||||||
|
delete r.second;
|
||||||
|
m_RouterInfos.clear ();
|
||||||
|
|
||||||
|
// load routers now
|
||||||
int numRouters = 0;
|
int numRouters = 0;
|
||||||
boost::filesystem::directory_iterator end;
|
boost::filesystem::directory_iterator end;
|
||||||
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
|
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
|
||||||
|
@ -247,7 +265,14 @@ namespace data
|
||||||
#endif
|
#endif
|
||||||
routerInfo->GetIdentHashBase64 () + ".dat";
|
routerInfo->GetIdentHashBase64 () + ".dat";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
boost::filesystem::path p (i2p::util::filesystem::GetDataDir());
|
||||||
|
p /= (directory);
|
||||||
|
#if BOOST_VERSION > 10500
|
||||||
|
const char * fullDirectory = p.string().c_str ();
|
||||||
|
#else
|
||||||
|
const char * fullDirectory = p.c_str ();
|
||||||
|
#endif
|
||||||
int count = 0, deletedCount = 0;
|
int count = 0, deletedCount = 0;
|
||||||
auto total = m_RouterInfos.size ();
|
auto total = m_RouterInfos.size ();
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
@ -255,7 +280,7 @@ namespace data
|
||||||
{
|
{
|
||||||
if (it.second->IsUpdated ())
|
if (it.second->IsUpdated ())
|
||||||
{
|
{
|
||||||
std::ofstream r (GetFilePath(directory, it.second), std::ofstream::binary);
|
std::ofstream r (GetFilePath(fullDirectory, 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++;
|
||||||
|
@ -271,9 +296,9 @@ namespace data
|
||||||
|
|
||||||
if (it.second->IsUnreachable ())
|
if (it.second->IsUnreachable ())
|
||||||
{
|
{
|
||||||
if (boost::filesystem::exists (GetFilePath (directory, it.second)))
|
if (boost::filesystem::exists (GetFilePath (fullDirectory, it.second)))
|
||||||
{
|
{
|
||||||
boost::filesystem::remove (GetFilePath (directory, it.second));
|
boost::filesystem::remove (GetFilePath (fullDirectory, it.second));
|
||||||
deletedCount++;
|
deletedCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -601,45 +626,5 @@ 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 ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
7
NetDb.h
7
NetDb.h
|
@ -6,6 +6,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
#include "Queue.h"
|
#include "Queue.h"
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
#include "RouterInfo.h"
|
#include "RouterInfo.h"
|
||||||
|
@ -76,10 +77,9 @@ namespace data
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool CreateNetDb(const char * directory);
|
bool CreateNetDb(boost::filesystem::path 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 std::set<IdentHash>& excluded) const;
|
const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||||
|
@ -95,8 +95,11 @@ namespace data
|
||||||
std::map<IdentHash, RequestedDestination *> m_RequestedDestinations;
|
std::map<IdentHash, RequestedDestination *> m_RequestedDestinations;
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
|
int m_ReseedRetries;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
i2p::util::Queue<I2NPMessage> m_Queue; // of I2NPDatabaseStoreMsg
|
i2p::util::Queue<I2NPMessage> m_Queue; // of I2NPDatabaseStoreMsg
|
||||||
|
|
||||||
|
static const char m_NetDbPath[];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern NetDb netdb;
|
extern NetDb netdb;
|
||||||
|
|
10
Queue.h
10
Queue.h
|
@ -98,13 +98,18 @@ namespace util
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MsgQueue (): m_Thread (std::bind (&MsgQueue<Msg>::Run, this)) {};
|
MsgQueue (): m_Thread (std::bind (&MsgQueue<Msg>::Run, this)) , running(1) {};
|
||||||
|
void Stop()
|
||||||
|
{
|
||||||
|
running = 0;
|
||||||
|
m_Thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Run ()
|
void Run ()
|
||||||
{
|
{
|
||||||
Msg * msg = nullptr;
|
Msg * msg = nullptr;
|
||||||
while ((msg = Queue<Msg>::GetNext ()) != nullptr)
|
while ((msg = Queue<Msg>::GetNext ()) != nullptr && running)
|
||||||
{
|
{
|
||||||
msg->Process ();
|
msg->Process ();
|
||||||
delete msg;
|
delete msg;
|
||||||
|
@ -113,6 +118,7 @@ namespace util
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::thread m_Thread;
|
std::thread m_Thread;
|
||||||
|
int running;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
36
README.md
36
README.md
|
@ -8,3 +8,39 @@ Requires gcc 4.6 and higher, boost 1.46 and higher, crypto++
|
||||||
on Windows
|
on Windows
|
||||||
|
|
||||||
Requires msvs2013, boost 1.46 and higher, crypto++
|
Requires msvs2013, boost 1.46 and higher, crypto++
|
||||||
|
|
||||||
|
|
||||||
|
Testing
|
||||||
|
-------
|
||||||
|
|
||||||
|
First, build it.
|
||||||
|
|
||||||
|
* $ cd i2pd
|
||||||
|
* $ make
|
||||||
|
|
||||||
|
Next, find out your public ip. (find it for example at http://www.whatismyip.com/)
|
||||||
|
|
||||||
|
Then, run it with:
|
||||||
|
|
||||||
|
$ ./i2p --host=YOUR_PUBLIC_IP
|
||||||
|
|
||||||
|
The client should now reseed by itself.
|
||||||
|
|
||||||
|
To visit an I2P page, you need to find the b32 address of your destination.
|
||||||
|
After that, go to the webconsole and add it behind the url. (Remove http:// and b32.i2p from the address)
|
||||||
|
|
||||||
|
This should resulting in for example:
|
||||||
|
http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa
|
||||||
|
|
||||||
|
|
||||||
|
Options
|
||||||
|
-------
|
||||||
|
|
||||||
|
* --host= - The external IP
|
||||||
|
* --port= - The port to listen on
|
||||||
|
* --httpport= - The http port to listen on
|
||||||
|
* --log= - Enable or disable logging to file. 1 for yes, 0 for no.
|
||||||
|
* --daemon= - Eanble or disable daemon mode. 1 for yes, 0 for no.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
101
Reseed.cpp
Normal file
101
Reseed.cpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <boost/regex.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include "Reseed.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace data
|
||||||
|
{
|
||||||
|
|
||||||
|
static std::vector<std::string> httpReseedHostList = {
|
||||||
|
"http://193.150.121.66/netDb/",
|
||||||
|
"http://netdb.i2p2.no/",
|
||||||
|
"http://reseed.i2p-projekt.de/",
|
||||||
|
"http://cowpuncher.drollette.com/netdb/",
|
||||||
|
"http://i2p.mooo.com/netDb/",
|
||||||
|
"http://reseed.info/",
|
||||||
|
"http://reseed.pkol.de/",
|
||||||
|
"http://uk.reseed.i2p2.no/",
|
||||||
|
"http://i2p-netdb.innovatio.no/",
|
||||||
|
"http://ieb9oopo.mooo.com"
|
||||||
|
};
|
||||||
|
|
||||||
|
//TODO: Implement v2 reseeding. Lightweight zip library is needed.
|
||||||
|
//TODO: Implement SU3, utils.
|
||||||
|
Reseeder::Reseeder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Reseeder::~Reseeder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Reseeder::reseedNow()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::string reseedHost = httpReseedHostList[(rand() % httpReseedHostList.size())];
|
||||||
|
LogPrint("Reseeding from ", reseedHost);
|
||||||
|
std::string content = i2p::util::http::httpRequest(reseedHost);
|
||||||
|
if (content == "")
|
||||||
|
{
|
||||||
|
LogPrint("Reseed failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boost::regex e("<\\s*A\\s+[^>]*href\\s*=\\s*\"([^\"]*)\"", boost::regex::normal | boost::regbase::icase);
|
||||||
|
boost::sregex_token_iterator i(content.begin(), content.end(), e, 1);
|
||||||
|
boost::sregex_token_iterator j;
|
||||||
|
//TODO: Ugly code, try to clean up.
|
||||||
|
//TODO: Try to reduce N number of variables
|
||||||
|
std::string name;
|
||||||
|
std::string routerInfo;
|
||||||
|
std::string tmpUrl;
|
||||||
|
std::string filename;
|
||||||
|
std::string ignoreFileSuffix = ".zip";
|
||||||
|
boost::filesystem::path root = i2p::util::filesystem::GetDataDir();
|
||||||
|
while (i != j)
|
||||||
|
{
|
||||||
|
name = *i++;
|
||||||
|
if (name.find(ignoreFileSuffix)!=std::string::npos)
|
||||||
|
continue;
|
||||||
|
LogPrint("Downloading ", name);
|
||||||
|
tmpUrl = reseedHost;
|
||||||
|
tmpUrl.append(name);
|
||||||
|
routerInfo = i2p::util::http::httpRequest(tmpUrl);
|
||||||
|
if (routerInfo.size()==0)
|
||||||
|
continue;
|
||||||
|
filename = root.string();
|
||||||
|
#ifndef _WIN32
|
||||||
|
filename += "/netDb/r";
|
||||||
|
#else
|
||||||
|
filename += "\\netDb\\r";
|
||||||
|
#endif
|
||||||
|
filename += name.at(11); // first char in id
|
||||||
|
#ifndef _WIN32
|
||||||
|
filename.append("/");
|
||||||
|
#else
|
||||||
|
filename.append("\\");
|
||||||
|
#endif
|
||||||
|
filename.append(name.c_str());
|
||||||
|
std::ofstream outfile (filename, std::ios::binary);
|
||||||
|
outfile << routerInfo;
|
||||||
|
outfile.close();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (std::exception& ex)
|
||||||
|
{
|
||||||
|
//TODO: error reporting
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
23
Reseed.h
Normal file
23
Reseed.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef RESEED_H
|
||||||
|
#define RESEED_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace data
|
||||||
|
{
|
||||||
|
|
||||||
|
class Reseeder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Reseeder();
|
||||||
|
~Reseeder();
|
||||||
|
bool reseedNow();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -52,6 +52,13 @@ namespace i2p
|
||||||
|
|
||||||
m_RouterInfo.CreateBuffer ();
|
m_RouterInfo.CreateBuffer ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RouterContext::UpdateAddress (const char * host)
|
||||||
|
{
|
||||||
|
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||||
|
address.host = boost::asio::ip::address::from_string (host);
|
||||||
|
m_RouterInfo.CreateBuffer ();
|
||||||
|
}
|
||||||
|
|
||||||
void RouterContext::Sign (uint8_t * buf, int len, uint8_t * signature)
|
void RouterContext::Sign (uint8_t * buf, int len, uint8_t * signature)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace i2p
|
||||||
void Sign (uint8_t * buf, int len, uint8_t * signature);
|
void Sign (uint8_t * buf, int len, uint8_t * signature);
|
||||||
|
|
||||||
void OverrideNTCPAddress (const char * host, int port); // temporary
|
void OverrideNTCPAddress (const char * host, int port); // temporary
|
||||||
|
void UpdateAddress (const char * host); // called from SSU
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,12 @@ namespace data
|
||||||
if (s.is_open ())
|
if (s.is_open ())
|
||||||
{
|
{
|
||||||
s.seekg (0,std::ios::end);
|
s.seekg (0,std::ios::end);
|
||||||
m_BufferLen = s.tellg ();
|
m_BufferLen = s.tellg ();
|
||||||
|
if (m_BufferLen < 40)
|
||||||
|
{
|
||||||
|
LogPrint("File", filename, " is malformed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
s.seekg(0, std::ios::beg);
|
s.seekg(0, std::ios::beg);
|
||||||
s.read(m_Buffer,m_BufferLen);
|
s.read(m_Buffer,m_BufferLen);
|
||||||
ReadFromBuffer ();
|
ReadFromBuffer ();
|
||||||
|
@ -289,6 +294,14 @@ namespace data
|
||||||
else
|
else
|
||||||
return m_SupportedTransports & (eNTCPV4 | eNTCPV6);
|
return m_SupportedTransports & (eNTCPV4 | eNTCPV6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RouterInfo::IsSSU (bool v4only) const
|
||||||
|
{
|
||||||
|
if (v4only)
|
||||||
|
return m_SupportedTransports & eSSUV4;
|
||||||
|
else
|
||||||
|
return m_SupportedTransports & (eSSUV4 | eSSUV6);
|
||||||
|
}
|
||||||
|
|
||||||
RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only)
|
RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only)
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace data
|
||||||
const char * GetIdentHashBase64 () const { return m_IdentHashBase64; };
|
const char * GetIdentHashBase64 () const { return m_IdentHashBase64; };
|
||||||
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; };
|
std::vector<Address>& GetAddresses () { return m_Addresses; };
|
||||||
Address * GetNTCPAddress (bool v4only = true);
|
Address * GetNTCPAddress (bool v4only = true);
|
||||||
Address * GetSSUAddress (bool v4only = true);
|
Address * GetSSUAddress (bool v4only = true);
|
||||||
const RoutingKey& GetRoutingKey () const { return m_RoutingKey; };
|
const RoutingKey& GetRoutingKey () const { return m_RoutingKey; };
|
||||||
|
@ -63,6 +63,7 @@ namespace data
|
||||||
const char * GetProperty (const char * key) const;
|
const char * GetProperty (const char * key) const;
|
||||||
bool IsFloodfill () const;
|
bool IsFloodfill () const;
|
||||||
bool IsNTCP (bool v4only = true) const;
|
bool IsNTCP (bool v4only = true) const;
|
||||||
|
bool IsSSU (bool v4only = true) const;
|
||||||
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
|
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; };
|
||||||
|
|
331
SSU.cpp
331
SSU.cpp
|
@ -20,7 +20,7 @@ namespace ssu
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::CreateAESKey (uint8_t * pubKey, uint8_t * aesKey) // TODO: move it to base class for NTCP and SSU
|
void SSUSession::CreateAESandMacKey (uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey)
|
||||||
{
|
{
|
||||||
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
|
||||||
CryptoPP::SecByteBlock secretKey(dh.AgreedValueLength());
|
CryptoPP::SecByteBlock secretKey(dh.AgreedValueLength());
|
||||||
|
@ -34,15 +34,24 @@ namespace ssu
|
||||||
{
|
{
|
||||||
aesKey[0] = 0;
|
aesKey[0] = 0;
|
||||||
memcpy (aesKey + 1, secretKey, 31);
|
memcpy (aesKey + 1, secretKey, 31);
|
||||||
|
memcpy (macKey, secretKey + 31, 32);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
memcpy (aesKey, secretKey, 32);
|
memcpy (aesKey, secretKey, 32);
|
||||||
|
memcpy (macKey, secretKey + 32, 32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||||
{
|
{
|
||||||
switch (m_State)
|
switch (m_State)
|
||||||
{
|
{
|
||||||
|
case eSessionStateEstablished:
|
||||||
|
// most common case
|
||||||
|
ProcessMessage (buf, len);
|
||||||
|
break;
|
||||||
|
// establishing
|
||||||
case eSessionStateUnknown:
|
case eSessionStateUnknown:
|
||||||
// session request
|
// session request
|
||||||
ProcessSessionRequest (buf, len, senderEndpoint);
|
ProcessSessionRequest (buf, len, senderEndpoint);
|
||||||
|
@ -51,33 +60,103 @@ namespace ssu
|
||||||
// session created
|
// session created
|
||||||
ProcessSessionCreated (buf, len);
|
ProcessSessionCreated (buf, len);
|
||||||
break;
|
break;
|
||||||
|
case eSessionStateCreatedSent:
|
||||||
|
// session confirmed
|
||||||
|
ProcessSessionConfirmed (buf, len);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint ("SSU state not implemented yet");
|
LogPrint ("SSU state not implemented yet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSUSession::ProcessMessage (uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
if (Validate (buf, len, m_MacKey))
|
||||||
|
{
|
||||||
|
Decrypt (buf, len, m_SessionKey);
|
||||||
|
SSUHeader * header = (SSUHeader *)buf;
|
||||||
|
uint8_t payloadType = header->flag >> 4;
|
||||||
|
switch (payloadType)
|
||||||
|
{
|
||||||
|
case PAYLOAD_TYPE_DATA:
|
||||||
|
LogPrint ("SSU data received");
|
||||||
|
ProcessData (buf + sizeof (SSUHeader), len - sizeof (SSUHeader));
|
||||||
|
break;
|
||||||
|
case PAYLOAD_TYPE_TEST:
|
||||||
|
LogPrint ("SSU test received");
|
||||||
|
break;
|
||||||
|
case PAYLOAD_TYPE_SESSION_DESTROYED:
|
||||||
|
LogPrint ("SSU session destroy received");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogPrint ("Unexpected SSU payload type ", (int)payloadType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: try intro key as well
|
||||||
|
else
|
||||||
|
LogPrint ("MAC verifcation failed");
|
||||||
|
}
|
||||||
|
|
||||||
void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||||
{
|
{
|
||||||
LogPrint ("Process session request");
|
LogPrint ("Process session request");
|
||||||
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, buf, len))
|
// use our intro key
|
||||||
|
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST,
|
||||||
|
i2p::context.GetRouterInfo (), buf, len))
|
||||||
{
|
{
|
||||||
m_State = eSessionStateRequestReceived;
|
m_State = eSessionStateRequestReceived;
|
||||||
LogPrint ("Session request received");
|
LogPrint ("Session request received");
|
||||||
SendSessionCreated (senderEndpoint);
|
m_RemoteEndpoint = senderEndpoint;
|
||||||
|
SendSessionCreated (buf + sizeof (SSUHeader));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len)
|
void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint ("Process session created");
|
LogPrint ("Process session created");
|
||||||
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, buf, len))
|
if (!m_RemoteRouter)
|
||||||
|
{
|
||||||
|
LogPrint ("Unsolicited session created message");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use remote intro key
|
||||||
|
if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, *m_RemoteRouter, buf, len))
|
||||||
{
|
{
|
||||||
m_State = eSessionStateCreatedReceived;
|
m_State = eSessionStateCreatedReceived;
|
||||||
LogPrint ("Session request received");
|
LogPrint ("Session created received");
|
||||||
// TODO:
|
uint8_t * ourAddress = buf + sizeof (SSUHeader) + 257;
|
||||||
|
boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )(ourAddress)));
|
||||||
|
uint16_t ourPort = be16toh (*(uint16_t *)(ourAddress + 4));
|
||||||
|
LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort);
|
||||||
|
i2p::context.UpdateAddress (ourIP.to_string ().c_str ());
|
||||||
|
uint32_t relayTag = be32toh (*(uint32_t *)(buf + sizeof (SSUHeader) + 263));
|
||||||
|
SendSessionConfirmed (buf + sizeof (SSUHeader), ourAddress, relayTag);
|
||||||
|
m_State = eSessionStateEstablished;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSUSession::ProcessSessionConfirmed (uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
LogPrint ("Process session confirmed");
|
||||||
|
if (Validate (buf, len, m_MacKey))
|
||||||
|
{
|
||||||
|
Decrypt (buf, len, m_SessionKey);
|
||||||
|
SSUHeader * header = (SSUHeader *)buf;
|
||||||
|
if ((header->flag >> 4) == PAYLOAD_TYPE_SESSION_CONFIRMED)
|
||||||
|
{
|
||||||
|
m_State = eSessionStateConfirmedReceived;
|
||||||
|
LogPrint ("Session confirmed received");
|
||||||
|
// TODO:
|
||||||
|
m_State = eSessionStateEstablished;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint ("Unexpected payload type ", (int)(header->flag >> 4));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint ("MAC verifcation failed");
|
||||||
|
}
|
||||||
|
|
||||||
void SSUSession::SendSessionRequest ()
|
void SSUSession::SendSessionRequest ()
|
||||||
{
|
{
|
||||||
auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr;
|
auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr;
|
||||||
|
@ -91,7 +170,7 @@ namespace ssu
|
||||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256);
|
memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256);
|
||||||
payload[256] = 4; // we assume ipv4
|
payload[256] = 4; // we assume ipv4
|
||||||
*(uint32_t *)(payload + 257) = address->host.to_v4 ().to_ulong (); // network bytes order already
|
*(uint32_t *)(payload + 257) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ());
|
||||||
|
|
||||||
uint8_t iv[16];
|
uint8_t iv[16];
|
||||||
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
|
@ -102,7 +181,53 @@ namespace ssu
|
||||||
m_Server->Send (buf, 304, m_RemoteEndpoint);
|
m_Server->Send (buf, 304, m_RemoteEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::SendSessionCreated (const boost::asio::ip::udp::endpoint& senderEndpoint)
|
void SSUSession::SendSessionCreated (const uint8_t * x)
|
||||||
|
{
|
||||||
|
auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr;
|
||||||
|
if (!address)
|
||||||
|
{
|
||||||
|
LogPrint ("Missing remote SSU address");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t signedData[532]; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time
|
||||||
|
memcpy (signedData, x, 256); // x
|
||||||
|
|
||||||
|
uint8_t buf[368 + 18];
|
||||||
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
|
memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256);
|
||||||
|
memcpy (signedData + 256, payload, 256); // y
|
||||||
|
payload += 256;
|
||||||
|
*payload = 4; // we assume ipv4
|
||||||
|
payload++;
|
||||||
|
*(uint32_t *)(payload) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ());
|
||||||
|
payload += 4;
|
||||||
|
*(uint16_t *)(payload) = htobe16 (m_RemoteEndpoint.port ());
|
||||||
|
payload += 2;
|
||||||
|
memcpy (signedData + 512, payload - 6, 6); // remote endpoint IP and port
|
||||||
|
*(uint32_t *)(signedData + 518) = htobe32 (m_Server->GetEndpoint ().address ().to_v4 ().to_ulong ()); // our IP
|
||||||
|
*(uint16_t *)(signedData + 522) = htobe16 (m_Server->GetEndpoint ().port ()); // our port
|
||||||
|
*(uint32_t *)(payload) = 0; // relay tag, always 0 for now
|
||||||
|
payload += 4;
|
||||||
|
*(uint32_t *)(payload) = htobe32 (i2p::util::GetSecondsSinceEpoch ()); // signed on time
|
||||||
|
payload += 4;
|
||||||
|
memcpy (signedData + 524, payload - 8, 8); // relayTag and signed on time
|
||||||
|
i2p::context.Sign (signedData, 532, payload); // DSA signature
|
||||||
|
// TODO: fill padding with random data
|
||||||
|
|
||||||
|
uint8_t iv[16];
|
||||||
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
|
rnd.GenerateBlock (iv, 16); // random iv
|
||||||
|
// encrypt signature and 8 bytes padding with newly created session key
|
||||||
|
m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv);
|
||||||
|
m_Encryption.ProcessData (payload, payload, 48);
|
||||||
|
|
||||||
|
// encrypt message with intro key
|
||||||
|
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, address->key, iv, address->key);
|
||||||
|
m_State = eSessionStateRequestSent;
|
||||||
|
m_Server->Send (buf, 368, m_RemoteEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag)
|
||||||
{
|
{
|
||||||
auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr;
|
auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr;
|
||||||
if (!address)
|
if (!address)
|
||||||
|
@ -111,17 +236,46 @@ namespace ssu
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t buf[368 + 18];
|
uint8_t buf[480 + 18];
|
||||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256);
|
*payload = 1; // 1 fragment
|
||||||
|
payload++; // info
|
||||||
|
size_t identLen = sizeof (i2p::context.GetRouterIdentity ()); // 387 bytes
|
||||||
|
*(uint16_t *)(payload) = htobe16 (identLen);
|
||||||
|
payload += 2; // cursize
|
||||||
|
memcpy (payload, (uint8_t *)&i2p::context.GetRouterIdentity (), identLen);
|
||||||
|
payload += identLen;
|
||||||
|
uint32_t signedOnTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
*(uint32_t *)(payload) = htobe32 (signedOnTime); // signed on time
|
||||||
|
payload += 4;
|
||||||
|
size_t paddingSize = ((payload - buf) + 40)%16;
|
||||||
|
if (paddingSize > 0) paddingSize = 16 - paddingSize;
|
||||||
|
// TODO: fill padding
|
||||||
|
payload += paddingSize; // padding size
|
||||||
|
|
||||||
m_State = eSessionStateRequestSent;
|
// signature
|
||||||
m_Server->Send (buf, 368, m_RemoteEndpoint);
|
uint8_t signedData[532]; // x,y, our IP, our port, remote IP, remote port, relayTag, our signed on time
|
||||||
|
memcpy (signedData, i2p::context.GetRouterIdentity ().publicKey, 256); // x
|
||||||
|
memcpy (signedData + 256, y, 256); // y
|
||||||
|
memcpy (signedData + 512, ourAddress, 6); // our address/port as seem by party
|
||||||
|
*(uint32_t *)(signedData + 518) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); // remote IP
|
||||||
|
*(uint16_t *)(signedData + 522) = htobe16 (m_RemoteEndpoint.port ()); // remote port
|
||||||
|
*(uint32_t *)(signedData + 524) = htobe32 (relayTag); // relay tag
|
||||||
|
*(uint32_t *)(signedData + 528) = htobe32 (signedOnTime); // signed on time
|
||||||
|
i2p::context.Sign (signedData, 532, payload); // DSA signature
|
||||||
|
|
||||||
|
uint8_t iv[16];
|
||||||
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
|
rnd.GenerateBlock (iv, 16); // random iv
|
||||||
|
// encrypt message with session key
|
||||||
|
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CONFIRMED, buf, 480, m_SessionKey, iv, m_MacKey);
|
||||||
|
m_State = eSessionStateConfirmedSent;
|
||||||
|
m_Server->Send (buf, 480, m_RemoteEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len)
|
bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
|
auto address = r.GetSSUAddress ();
|
||||||
if (address)
|
if (address)
|
||||||
{
|
{
|
||||||
// use intro key for verification and decryption
|
// use intro key for verification and decryption
|
||||||
|
@ -131,7 +285,7 @@ namespace ssu
|
||||||
SSUHeader * header = (SSUHeader *)buf;
|
SSUHeader * header = (SSUHeader *)buf;
|
||||||
if ((header->flag >> 4) == expectedPayloadType)
|
if ((header->flag >> 4) == expectedPayloadType)
|
||||||
{
|
{
|
||||||
CreateAESKey (buf + sizeof (SSUHeader), m_SessionKey);
|
CreateAESandMacKey (buf + sizeof (SSUHeader), m_SessionKey, m_MacKey);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -141,7 +295,7 @@ namespace ssu
|
||||||
LogPrint ("MAC verifcation failed");
|
LogPrint ("MAC verifcation failed");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint ("SSU is not supported");
|
LogPrint ("SSU is not supported by ", r.GetIdentHashAbbreviation ());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +331,7 @@ namespace ssu
|
||||||
uint8_t * encrypted = &header->flag;
|
uint8_t * encrypted = &header->flag;
|
||||||
uint16_t encryptedLen = len - (encrypted - buf);
|
uint16_t encryptedLen = len - (encrypted - buf);
|
||||||
m_Decryption.SetKeyWithIV (aesKey, 32, header->iv);
|
m_Decryption.SetKeyWithIV (aesKey, 32, header->iv);
|
||||||
|
encryptedLen = (encryptedLen/16)*16; // make sure 16 bytes boundary
|
||||||
m_Decryption.ProcessData (encrypted, encrypted, encryptedLen);
|
m_Decryption.ProcessData (encrypted, encrypted, encryptedLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,14 +358,132 @@ namespace ssu
|
||||||
SendSessionRequest ();
|
SendSessionRequest ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSUSession::Close ()
|
||||||
|
{
|
||||||
|
SendSesionDestroyed ();
|
||||||
|
}
|
||||||
|
|
||||||
void SSUSession::SendI2NPMessage (I2NPMessage * msg)
|
void SSUSession::SendI2NPMessage (I2NPMessage * msg)
|
||||||
{
|
{
|
||||||
// TODO:
|
// TODO:
|
||||||
}
|
}
|
||||||
|
|
||||||
SSUServer::SSUServer (boost::asio::io_service& service, int port):
|
void SSUSession::ProcessData (uint8_t * buf, size_t len)
|
||||||
m_Socket (service, boost::asio::ip::udp::endpoint (boost::asio::ip::udp::v4 (), port))
|
|
||||||
{
|
{
|
||||||
|
//uint8_t * start = buf;
|
||||||
|
uint8_t flag = *buf;
|
||||||
|
buf++;
|
||||||
|
LogPrint ("Process SSU data flags=", (int)flag);
|
||||||
|
if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED)
|
||||||
|
{
|
||||||
|
// explicit ACKs
|
||||||
|
uint8_t numAcks =*buf;
|
||||||
|
buf++;
|
||||||
|
// TODO: process ACKs
|
||||||
|
buf += numAcks*4;
|
||||||
|
}
|
||||||
|
if (flag & DATA_FLAG_ACK_BITFIELDS_INCLUDED)
|
||||||
|
{
|
||||||
|
// explicit ACK bitfields
|
||||||
|
uint8_t numBitfields =*buf;
|
||||||
|
buf++;
|
||||||
|
for (int i = 0; i < numBitfields; i++)
|
||||||
|
{
|
||||||
|
buf += 4; // msgID
|
||||||
|
// TODO: process ACH bitfields
|
||||||
|
while (*buf & 0x80) // not last
|
||||||
|
buf++;
|
||||||
|
buf++; // last byte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint8_t numFragments = *buf; // number of fragments
|
||||||
|
buf++;
|
||||||
|
for (int i = 0; i < numFragments; i++)
|
||||||
|
{
|
||||||
|
uint32_t msgID = be32toh (*(uint32_t *)buf); // message ID
|
||||||
|
buf += 4;
|
||||||
|
uint8_t frag[4];
|
||||||
|
frag[0] = 0;
|
||||||
|
memcpy (frag + 1, buf, 3);
|
||||||
|
buf += 3;
|
||||||
|
uint32_t fragmentInfo = be32toh (*(uint32_t *)frag); // fragment info
|
||||||
|
uint16_t fragmentSize = fragmentInfo & 0x1FFF; // bits 0 - 13
|
||||||
|
bool isLast = fragmentInfo & 0x010000; // bit 16
|
||||||
|
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
|
||||||
|
LogPrint ("SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last");
|
||||||
|
I2NPMessage * msg = nullptr;
|
||||||
|
if (fragmentNum > 0) // follow-up fragment
|
||||||
|
{
|
||||||
|
auto it = m_IncomleteMessages.find (msgID);
|
||||||
|
if (it != m_IncomleteMessages.end ())
|
||||||
|
{
|
||||||
|
msg = it->second;
|
||||||
|
memcpy (msg->buf + msg->len, buf, fragmentSize);
|
||||||
|
msg->len += fragmentSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// TODO:
|
||||||
|
LogPrint ("Unexpected follow-on fragment ", fragmentNum, " of message ", msgID);
|
||||||
|
}
|
||||||
|
else // first fragment
|
||||||
|
{
|
||||||
|
msg = NewI2NPMessage ();
|
||||||
|
memcpy (msg->GetSSUHeader (), buf, fragmentSize);
|
||||||
|
msg->len += fragmentSize - sizeof (I2NPHeaderShort);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg)
|
||||||
|
{
|
||||||
|
if (!fragmentNum && !isLast)
|
||||||
|
m_IncomleteMessages[msgID] = msg;
|
||||||
|
if (isLast)
|
||||||
|
{
|
||||||
|
if (fragmentNum > 0)
|
||||||
|
m_IncomleteMessages.erase (msgID);
|
||||||
|
msg->FromSSU (msgID);
|
||||||
|
i2p::HandleI2NPMessage (msg, false);
|
||||||
|
SendMsgAck (msgID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf += fragmentSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::SendMsgAck (uint32_t msgID)
|
||||||
|
{
|
||||||
|
uint8_t buf[48 + 18]; // actual length is 44 = 37 + 7 but pad it to multiple of 16
|
||||||
|
uint8_t iv[16];
|
||||||
|
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||||
|
*payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag
|
||||||
|
payload++;
|
||||||
|
*payload = 1; // number of ACKs
|
||||||
|
payload++;
|
||||||
|
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
|
||||||
|
payload += 4;
|
||||||
|
*payload = 0; // number of fragments
|
||||||
|
|
||||||
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
|
rnd.GenerateBlock (iv, 16); // random iv
|
||||||
|
// encrypt message with session key
|
||||||
|
FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48, m_SessionKey, iv, m_MacKey);
|
||||||
|
m_Server->Send (buf, 48, m_RemoteEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::SendSesionDestroyed ()
|
||||||
|
{
|
||||||
|
uint8_t buf[48 + 18], iv[16];
|
||||||
|
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
|
||||||
|
rnd.GenerateBlock (iv, 16); // random iv
|
||||||
|
// encrypt message with session key
|
||||||
|
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey);
|
||||||
|
m_Server->Send (buf, 48, m_RemoteEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
SSUServer::SSUServer (boost::asio::io_service& service, int port):
|
||||||
|
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint)
|
||||||
|
{
|
||||||
|
m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (65535));
|
||||||
|
m_Socket.set_option (boost::asio::socket_base::send_buffer_size (65535));
|
||||||
}
|
}
|
||||||
|
|
||||||
SSUServer::~SSUServer ()
|
SSUServer::~SSUServer ()
|
||||||
|
@ -289,6 +562,26 @@ namespace ssu
|
||||||
}
|
}
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SSUServer::DeleteSession (SSUSession * session)
|
||||||
|
{
|
||||||
|
if (session)
|
||||||
|
{
|
||||||
|
session->Close ();
|
||||||
|
m_Sessions.erase (session->GetRemoteEndpoint ());
|
||||||
|
delete session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUServer::DeleteAllSessions ()
|
||||||
|
{
|
||||||
|
for (auto it: m_Sessions)
|
||||||
|
{
|
||||||
|
it.second->Close ();
|
||||||
|
delete it.second;
|
||||||
|
}
|
||||||
|
m_Sessions.clear ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
SSU.h
36
SSU.h
|
@ -26,7 +26,7 @@ namespace ssu
|
||||||
|
|
||||||
const int SSU_MTU = 1484;
|
const int SSU_MTU = 1484;
|
||||||
|
|
||||||
// payload types (3 bits)
|
// payload types (4 bits)
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
|
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1;
|
const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1;
|
||||||
const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2;
|
const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2;
|
||||||
|
@ -35,6 +35,15 @@ namespace ssu
|
||||||
const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
|
const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
|
||||||
const uint8_t PAYLOAD_TYPE_DATA = 6;
|
const uint8_t PAYLOAD_TYPE_DATA = 6;
|
||||||
const uint8_t PAYLOAD_TYPE_TEST = 7;
|
const uint8_t PAYLOAD_TYPE_TEST = 7;
|
||||||
|
const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
|
||||||
|
|
||||||
|
// data flags
|
||||||
|
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
|
||||||
|
const uint8_t DATA_FLAG_WANT_REPLY = 0x04;
|
||||||
|
const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08;
|
||||||
|
const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10;
|
||||||
|
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
|
||||||
|
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
|
||||||
|
|
||||||
enum SessionState
|
enum SessionState
|
||||||
{
|
{
|
||||||
|
@ -45,7 +54,7 @@ namespace ssu
|
||||||
eSessionStateCreatedReceived,
|
eSessionStateCreatedReceived,
|
||||||
eSessionStateConfirmedSent,
|
eSessionStateConfirmedSent,
|
||||||
eSessionStateConfirmedReceived,
|
eSessionStateConfirmedReceived,
|
||||||
eSessionStateEstablised
|
eSessionStateEstablished
|
||||||
};
|
};
|
||||||
|
|
||||||
class SSUServer;
|
class SSUServer;
|
||||||
|
@ -58,18 +67,26 @@ namespace ssu
|
||||||
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
||||||
|
|
||||||
void Connect ();
|
void Connect ();
|
||||||
|
void Close ();
|
||||||
|
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
||||||
void SendI2NPMessage (I2NPMessage * msg);
|
void SendI2NPMessage (I2NPMessage * msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateAESKey (uint8_t * pubKey, uint8_t * aesKey); // TODO: shouldn't be here
|
void CreateAESandMacKey (uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey);
|
||||||
|
|
||||||
|
void ProcessMessage (uint8_t * buf, size_t len); // call for established session
|
||||||
void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
||||||
void SendSessionRequest ();
|
void SendSessionRequest ();
|
||||||
void ProcessSessionCreated (uint8_t * buf, size_t len);
|
void ProcessSessionCreated (uint8_t * buf, size_t len);
|
||||||
void SendSessionCreated (const boost::asio::ip::udp::endpoint& senderEndpoint);
|
void SendSessionCreated (const uint8_t * x);
|
||||||
|
void ProcessSessionConfirmed (uint8_t * buf, size_t len);
|
||||||
bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len);
|
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag);
|
||||||
|
void ProcessData (uint8_t * buf, size_t len);
|
||||||
|
void SendMsgAck (uint32_t msgID);
|
||||||
|
void SendSesionDestroyed ();
|
||||||
|
|
||||||
|
bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, 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 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);
|
void Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey);
|
||||||
bool Validate (uint8_t * buf, size_t len, uint8_t * macKey);
|
bool Validate (uint8_t * buf, size_t len, uint8_t * macKey);
|
||||||
|
@ -82,7 +99,8 @@ namespace ssu
|
||||||
SessionState m_State;
|
SessionState m_State;
|
||||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption;
|
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption;
|
||||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption;
|
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption;
|
||||||
uint8_t m_SessionKey[32];
|
uint8_t m_SessionKey[32], m_MacKey[32];
|
||||||
|
std::map<uint32_t, I2NPMessage *> m_IncomleteMessages;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SSUServer
|
class SSUServer
|
||||||
|
@ -94,7 +112,10 @@ namespace ssu
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
SSUSession * GetSession (i2p::data::RouterInfo * router);
|
SSUSession * GetSession (i2p::data::RouterInfo * router);
|
||||||
|
void DeleteSession (SSUSession * session);
|
||||||
|
void DeleteAllSessions ();
|
||||||
|
|
||||||
|
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
|
||||||
void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
|
void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -104,6 +125,7 @@ namespace ssu
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
boost::asio::ip::udp::endpoint m_Endpoint;
|
||||||
boost::asio::ip::udp::socket m_Socket;
|
boost::asio::ip::udp::socket m_Socket;
|
||||||
boost::asio::ip::udp::endpoint m_SenderEndpoint;
|
boost::asio::ip::udp::endpoint m_SenderEndpoint;
|
||||||
uint8_t m_ReceiveBuffer[2*SSU_MTU];
|
uint8_t m_ReceiveBuffer[2*SSU_MTU];
|
||||||
|
|
104
Streaming.cpp
104
Streaming.cpp
|
@ -34,55 +34,22 @@ namespace stream
|
||||||
if (!m_SendStreamID)
|
if (!m_SendStreamID)
|
||||||
m_SendStreamID = packet->GetReceiveStreamID ();
|
m_SendStreamID = packet->GetReceiveStreamID ();
|
||||||
|
|
||||||
// process flags
|
|
||||||
uint16_t flags = packet->GetFlags ();
|
|
||||||
const uint8_t * optionData = packet->GetOptionData ();
|
|
||||||
if (flags & PACKET_FLAG_SYNCHRONIZE)
|
|
||||||
{
|
|
||||||
LogPrint ("Synchronize");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
|
||||||
{
|
|
||||||
LogPrint ("Signature");
|
|
||||||
optionData += 40;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & PACKET_FLAG_FROM_INCLUDED)
|
|
||||||
{
|
|
||||||
LogPrint ("From identity");
|
|
||||||
optionData += sizeof (i2p::data::Identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t receivedSeqn = packet->GetSeqn ();
|
uint32_t receivedSeqn = packet->GetSeqn ();
|
||||||
LogPrint ("seqn=", receivedSeqn, ", flags=", flags);
|
LogPrint ("Received seqn=", receivedSeqn);
|
||||||
if (!receivedSeqn || receivedSeqn == m_LastReceivedSequenceNumber + 1)
|
if (!receivedSeqn || receivedSeqn == m_LastReceivedSequenceNumber + 1)
|
||||||
{
|
{
|
||||||
// we have received next message
|
// we have received next in sequence message
|
||||||
packet->offset = packet->GetPayload () - packet->buf;
|
ProcessPacket (packet);
|
||||||
if (packet->GetLength () > 0)
|
|
||||||
m_ReceiveQueue.Put (packet);
|
|
||||||
else
|
|
||||||
delete packet;
|
|
||||||
|
|
||||||
m_LastReceivedSequenceNumber = receivedSeqn;
|
|
||||||
SendQuickAck ();
|
|
||||||
|
|
||||||
// we should also try stored messages if any
|
// we should also try stored messages if any
|
||||||
for (auto it = m_SavedPackets.begin (); it != m_SavedPackets.end ();)
|
for (auto it = m_SavedPackets.begin (); it != m_SavedPackets.end ();)
|
||||||
{
|
{
|
||||||
if ((*it)->GetSeqn () == m_LastReceivedSequenceNumber + 1)
|
if ((*it)->GetSeqn () == m_LastReceivedSequenceNumber + 1)
|
||||||
{
|
{
|
||||||
Packet * packet = *it;
|
Packet * savedPacket = *it;
|
||||||
m_SavedPackets.erase (it++);
|
m_SavedPackets.erase (it++);
|
||||||
|
|
||||||
LogPrint ("Process saved packet seqn=", packet->GetSeqn ());
|
ProcessPacket (savedPacket);
|
||||||
if (packet->GetLength () > 0)
|
|
||||||
m_ReceiveQueue.Put (packet);
|
|
||||||
else
|
|
||||||
delete packet;
|
|
||||||
m_LastReceivedSequenceNumber++;
|
|
||||||
SendQuickAck ();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
@ -106,7 +73,47 @@ namespace stream
|
||||||
SavePacket (packet);
|
SavePacket (packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::SavePacket (Packet * packet)
|
||||||
|
{
|
||||||
|
m_SavedPackets.insert (packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::ProcessPacket (Packet * packet)
|
||||||
|
{
|
||||||
|
// process flags
|
||||||
|
uint32_t receivedSeqn = packet->GetSeqn ();
|
||||||
|
uint16_t flags = packet->GetFlags ();
|
||||||
|
LogPrint ("Process seqn=", receivedSeqn, ", flags=", flags);
|
||||||
|
|
||||||
|
const uint8_t * optionData = packet->GetOptionData ();
|
||||||
|
if (flags & PACKET_FLAG_SYNCHRONIZE)
|
||||||
|
{
|
||||||
|
LogPrint ("Synchronize");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
||||||
|
{
|
||||||
|
LogPrint ("Signature");
|
||||||
|
optionData += 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & PACKET_FLAG_FROM_INCLUDED)
|
||||||
|
{
|
||||||
|
LogPrint ("From identity");
|
||||||
|
optionData += sizeof (i2p::data::Identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
packet->offset = packet->GetPayload () - packet->buf;
|
||||||
|
if (packet->GetLength () > 0)
|
||||||
|
m_ReceiveQueue.Put (packet);
|
||||||
|
else
|
||||||
|
delete packet;
|
||||||
|
|
||||||
|
m_LastReceivedSequenceNumber = receivedSeqn;
|
||||||
|
SendQuickAck ();
|
||||||
|
|
||||||
if (flags & PACKET_FLAG_CLOSE)
|
if (flags & PACKET_FLAG_CLOSE)
|
||||||
{
|
{
|
||||||
LogPrint ("Closed");
|
LogPrint ("Closed");
|
||||||
|
@ -114,11 +121,6 @@ namespace stream
|
||||||
m_ReceiveQueue.WakeUp ();
|
m_ReceiveQueue.WakeUp ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -170,9 +172,10 @@ namespace stream
|
||||||
|
|
||||||
if (!m_OutboundTunnel)
|
if (!m_OutboundTunnel)
|
||||||
m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel ();
|
m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel ();
|
||||||
if (m_OutboundTunnel)
|
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases ();
|
||||||
|
if (m_OutboundTunnel && !leases.empty ())
|
||||||
{
|
{
|
||||||
auto& lease = m_RemoteLeaseSet->GetLeases ()[0]; // TODO:
|
auto& lease = *leases.begin (); // TODO:
|
||||||
m_OutboundTunnel->SendTunnelDataMsg (lease.tunnelGateway, lease.tunnelID, msg);
|
m_OutboundTunnel->SendTunnelDataMsg (lease.tunnelGateway, lease.tunnelID, msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -206,7 +209,7 @@ namespace stream
|
||||||
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases ();
|
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases ();
|
||||||
if (!leases.empty ())
|
if (!leases.empty ())
|
||||||
{
|
{
|
||||||
auto& lease = leases[0]; // TODO:
|
auto& lease = *leases.begin (); // TODO:
|
||||||
m_OutboundTunnel->SendTunnelDataMsg (lease.tunnelGateway, lease.tunnelID, msg);
|
m_OutboundTunnel->SendTunnelDataMsg (lease.tunnelGateway, lease.tunnelID, msg);
|
||||||
LogPrint ("Quick Ack sent");
|
LogPrint ("Quick Ack sent");
|
||||||
}
|
}
|
||||||
|
@ -249,11 +252,12 @@ namespace stream
|
||||||
|
|
||||||
I2NPMessage * msg = i2p::garlic::routing.WrapSingleMessage (m_RemoteLeaseSet,
|
I2NPMessage * msg = i2p::garlic::routing.WrapSingleMessage (m_RemoteLeaseSet,
|
||||||
CreateDataMessage (this, packet, size));
|
CreateDataMessage (this, packet, size));
|
||||||
if (m_OutboundTunnel)
|
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases ();
|
||||||
|
if (m_OutboundTunnel && !leases.empty ())
|
||||||
{
|
{
|
||||||
auto& lease = m_RemoteLeaseSet->GetLeases ()[0]; // TODO:
|
auto& lease = *leases.begin (); // TODO:
|
||||||
m_OutboundTunnel->SendTunnelDataMsg (lease.tunnelGateway, lease.tunnelID, msg);
|
m_OutboundTunnel->SendTunnelDataMsg (lease.tunnelGateway, lease.tunnelID, msg);
|
||||||
LogPrint ("FIN sent");
|
LogPrint ("FIN sent");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DeleteI2NPMessage (msg);
|
DeleteI2NPMessage (msg);
|
||||||
|
|
|
@ -84,6 +84,7 @@ namespace stream
|
||||||
void SendQuickAck ();
|
void SendQuickAck ();
|
||||||
|
|
||||||
void SavePacket (Packet * packet);
|
void SavePacket (Packet * packet);
|
||||||
|
void ProcessPacket (Packet * packet);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ namespace i2p
|
||||||
{
|
{
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&Transports::Run, this));
|
m_Thread = new std::thread (std::bind (&Transports::Run, this));
|
||||||
|
m_Timer = new boost::asio::deadline_timer (m_Service);
|
||||||
// create acceptors
|
// create acceptors
|
||||||
auto addresses = context.GetRouterInfo ().GetAddresses ();
|
auto addresses = context.GetRouterInfo ().GetAddresses ();
|
||||||
for (auto& address : addresses)
|
for (auto& address : addresses)
|
||||||
|
@ -38,9 +39,11 @@ namespace i2p
|
||||||
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));
|
||||||
}
|
// temporary always run SSU server
|
||||||
|
// TODO: uncomment following lines later
|
||||||
|
/*}
|
||||||
else if (address.transportStyle == RouterInfo::eTransportSSU)
|
else if (address.transportStyle == RouterInfo::eTransportSSU)
|
||||||
{
|
{*/
|
||||||
if (!m_SSUServer)
|
if (!m_SSUServer)
|
||||||
{
|
{
|
||||||
m_SSUServer = new i2p::ssu::SSUServer (m_Service, address.port);
|
m_SSUServer = new i2p::ssu::SSUServer (m_Service, address.port);
|
||||||
|
@ -51,6 +54,9 @@ namespace i2p
|
||||||
LogPrint ("SSU server already exists");
|
LogPrint ("SSU server already exists");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: do it for SSU only
|
||||||
|
DetectExternalIP ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::Stop ()
|
void Transports::Stop ()
|
||||||
|
@ -59,7 +65,10 @@ namespace i2p
|
||||||
delete session.second;
|
delete session.second;
|
||||||
m_NTCPSessions.clear ();
|
m_NTCPSessions.clear ();
|
||||||
delete m_NTCPAcceptor;
|
delete m_NTCPAcceptor;
|
||||||
|
|
||||||
|
m_Timer->cancel ();
|
||||||
|
delete m_Timer;
|
||||||
|
|
||||||
if (m_SSUServer)
|
if (m_SSUServer)
|
||||||
{
|
{
|
||||||
m_SSUServer->Stop ();
|
m_SSUServer->Stop ();
|
||||||
|
@ -173,4 +182,30 @@ namespace i2p
|
||||||
else
|
else
|
||||||
LogPrint ("Session not found");
|
LogPrint ("Session not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Transports::DetectExternalIP ()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 5; i ++)
|
||||||
|
{
|
||||||
|
auto router = i2p::data::netdb.GetRandomRouter ();
|
||||||
|
if (router && router->IsSSU () && m_SSUServer)
|
||||||
|
m_SSUServer->GetSession (const_cast<i2p::data::RouterInfo *>(router)); //TODO
|
||||||
|
}
|
||||||
|
if (m_Timer)
|
||||||
|
{
|
||||||
|
m_Timer->expires_from_now (boost::posix_time::seconds(5)); // 5 seconds
|
||||||
|
m_Timer->async_wait (boost::bind (&Transports::HandleTimer, this, boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transports::HandleTimer (const boost::system::error_code& ecode)
|
||||||
|
{
|
||||||
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
// end of external IP detection
|
||||||
|
if (m_SSUServer)
|
||||||
|
m_SSUServer->DeleteAllSessions ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,9 @@ namespace i2p
|
||||||
void Run ();
|
void Run ();
|
||||||
void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error);
|
void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error);
|
||||||
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
|
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
|
||||||
|
|
||||||
|
void DetectExternalIP ();
|
||||||
|
void HandleTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -49,6 +52,7 @@ namespace i2p
|
||||||
|
|
||||||
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;
|
i2p::ssu::SSUServer * m_SSUServer;
|
||||||
|
boost::asio::deadline_timer * m_Timer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<ClCompile Include="..\Log.cpp" />
|
<ClCompile Include="..\Log.cpp" />
|
||||||
<ClCompile Include="..\NetDb.cpp" />
|
<ClCompile Include="..\NetDb.cpp" />
|
||||||
<ClCompile Include="..\NTCPSession.cpp" />
|
<ClCompile Include="..\NTCPSession.cpp" />
|
||||||
|
<ClCompile Include="..\Reseed.cpp" />
|
||||||
<ClCompile Include="..\RouterContext.cpp" />
|
<ClCompile Include="..\RouterContext.cpp" />
|
||||||
<ClCompile Include="..\RouterInfo.cpp" />
|
<ClCompile Include="..\RouterInfo.cpp" />
|
||||||
<ClCompile Include="..\SSU.cpp" />
|
<ClCompile Include="..\SSU.cpp" />
|
||||||
|
@ -31,6 +32,7 @@
|
||||||
<ClCompile Include="..\Tunnel.cpp" />
|
<ClCompile Include="..\Tunnel.cpp" />
|
||||||
<ClCompile Include="..\TunnelEndpoint.cpp" />
|
<ClCompile Include="..\TunnelEndpoint.cpp" />
|
||||||
<ClCompile Include="..\TunnelGateway.cpp" />
|
<ClCompile Include="..\TunnelGateway.cpp" />
|
||||||
|
<ClCompile Include="..\util.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\base64.h" />
|
<ClInclude Include="..\base64.h" />
|
||||||
|
@ -47,6 +49,7 @@
|
||||||
<ClInclude Include="..\NetDb.h" />
|
<ClInclude Include="..\NetDb.h" />
|
||||||
<ClInclude Include="..\NTCPSession.h" />
|
<ClInclude Include="..\NTCPSession.h" />
|
||||||
<ClInclude Include="..\Queue.h" />
|
<ClInclude Include="..\Queue.h" />
|
||||||
|
<ClInclude Include="..\Reseed.h" />
|
||||||
<ClInclude Include="..\RouterContext.h" />
|
<ClInclude Include="..\RouterContext.h" />
|
||||||
<ClInclude Include="..\RouterInfo.h" />
|
<ClInclude Include="..\RouterInfo.h" />
|
||||||
<ClInclude Include="..\SSU.h" />
|
<ClInclude Include="..\SSU.h" />
|
||||||
|
@ -59,6 +62,7 @@
|
||||||
<ClInclude Include="..\TunnelConfig.h" />
|
<ClInclude Include="..\TunnelConfig.h" />
|
||||||
<ClInclude Include="..\TunnelEndpoint.h" />
|
<ClInclude Include="..\TunnelEndpoint.h" />
|
||||||
<ClInclude Include="..\TunnelGateway.h" />
|
<ClInclude Include="..\TunnelGateway.h" />
|
||||||
|
<ClInclude Include="..\util.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{930568EC-31C9-406A-AD1C-9636DF5D8FAA}</ProjectGuid>
|
<ProjectGuid>{930568EC-31C9-406A-AD1C-9636DF5D8FAA}</ProjectGuid>
|
||||||
|
|
|
@ -75,6 +75,12 @@
|
||||||
<ClCompile Include="..\SSU.cpp">
|
<ClCompile Include="..\SSU.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\util.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Reseed.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\Identity.h">
|
<ClInclude Include="..\Identity.h">
|
||||||
|
@ -155,5 +161,11 @@
|
||||||
<ClInclude Include="..\SSU.h">
|
<ClInclude Include="..\SSU.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\util.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\Reseed.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
5
hmac.h
5
hmac.h
|
@ -18,7 +18,6 @@ namespace crypto
|
||||||
// digest is 16 bytes
|
// digest is 16 bytes
|
||||||
// block size is 64 bytes
|
// block size is 64 bytes
|
||||||
{
|
{
|
||||||
size_t totalLen = len + 64 + 32;
|
|
||||||
uint8_t buf[2048];
|
uint8_t buf[2048];
|
||||||
// ikeypad
|
// ikeypad
|
||||||
((uint64_t *)buf)[0] = ((uint64_t *)key)[0] ^ IPAD;
|
((uint64_t *)buf)[0] = ((uint64_t *)key)[0] ^ IPAD;
|
||||||
|
@ -47,10 +46,10 @@ namespace crypto
|
||||||
// copy first hash after okeypad
|
// copy first hash after okeypad
|
||||||
memcpy (buf + 64, hash, 16);
|
memcpy (buf + 64, hash, 16);
|
||||||
// fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
|
// fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
|
||||||
memset (buf + 72, 0, 16);
|
memset (buf + 80, 0, 16);
|
||||||
|
|
||||||
// calculate digest
|
// calculate digest
|
||||||
CryptoPP::Weak1::MD5().CalculateDigest (digest, buf, totalLen);
|
CryptoPP::Weak1::MD5().CalculateDigest (digest, buf, 96);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
161
i2p.cpp
161
i2p.cpp
|
@ -1,6 +1,18 @@
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS // to use freopen
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <cryptopp/integer.h>
|
#include <cryptopp/integer.h>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
#include "Transports.h"
|
#include "Transports.h"
|
||||||
|
@ -12,9 +24,43 @@
|
||||||
#include "HTTPServer.h"
|
#include "HTTPServer.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Global
|
||||||
|
int running = 1;
|
||||||
|
int isDaemon;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
void handle_signal(int sig)
|
||||||
|
{
|
||||||
|
switch (sig)
|
||||||
|
{
|
||||||
|
case SIGHUP:
|
||||||
|
if (i2p::util::config::GetArg("daemon", 0) == 1)
|
||||||
|
{
|
||||||
|
static bool first=true;
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
first=false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LogPrint("Reloading config.");
|
||||||
|
i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
|
||||||
|
break;
|
||||||
|
case SIGABRT:
|
||||||
|
case SIGTERM:
|
||||||
|
case SIGINT:
|
||||||
|
running = 0; // Exit loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int main( int argc, char* argv[] )
|
int main( int argc, char* argv[] )
|
||||||
{
|
{
|
||||||
i2p::util::ParseArguments(argc,argv);
|
i2p::util::config::OptionParser(argc,argv);
|
||||||
|
isDaemon = i2p::util::config::GetArg("-daemon", 0);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
setlocale(LC_CTYPE, "");
|
setlocale(LC_CTYPE, "");
|
||||||
SetConsoleCP(1251);
|
SetConsoleCP(1251);
|
||||||
|
@ -22,19 +68,110 @@ int main( int argc, char* argv[] )
|
||||||
setlocale(LC_ALL, "Russian");
|
setlocale(LC_ALL, "Russian");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int httpport = i2p::util::GetIntArg("--httpport", 7070);
|
|
||||||
|
|
||||||
i2p::util::HTTPServer httpServer (httpport);
|
LogPrint("\n\n\n\ni2pd starting\n");
|
||||||
|
LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string());
|
||||||
|
i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
|
||||||
|
|
||||||
httpServer.Start ();
|
int isLogging = i2p::util::config::GetArg("-log", 0);
|
||||||
|
if (isLogging == 1)
|
||||||
|
{
|
||||||
|
std::string logfile = i2p::util::filesystem::GetDataDir().string();
|
||||||
|
#ifndef _WIN32
|
||||||
|
logfile.append("/debug.log");
|
||||||
|
#else
|
||||||
|
logfile.append("\\debug.log");
|
||||||
|
#endif
|
||||||
|
freopen(logfile.c_str(),"a",stdout);
|
||||||
|
LogPrint("Logging to file enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
if (isDaemon == 1)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
pid = fork();
|
||||||
|
if (pid > 0)
|
||||||
|
{
|
||||||
|
g_Log.Stop();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (pid < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
umask(0);
|
||||||
|
int sid = setsid();
|
||||||
|
if (sid < 0)
|
||||||
|
{
|
||||||
|
LogPrint("Error, could not create process group.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
chdir(i2p::util::filesystem::GetDataDir().string().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pidfile
|
||||||
|
std::string pidfile = i2p::util::filesystem::GetDataDir().string();
|
||||||
|
pidfile.append("/i2pd.pid");
|
||||||
|
int pidFilehandle = open(pidfile.c_str(), O_RDWR|O_CREAT, 0600);
|
||||||
|
if (pidFilehandle == -1 )
|
||||||
|
{
|
||||||
|
LogPrint("Error, could not create pid file (", pidfile, ")\nIs an instance already running?");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (lockf(pidFilehandle,F_TLOCK,0) == -1)
|
||||||
|
{
|
||||||
|
LogPrint("Error, could not lock pid file (", pidfile, ")\nIs an instance already running?");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char pid[10];
|
||||||
|
sprintf(pid,"%d\n",getpid());
|
||||||
|
write(pidFilehandle, pid, strlen(pid));
|
||||||
|
|
||||||
|
// Signal handler
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = handle_signal;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
sigaction(SIGHUP,&sa,0);
|
||||||
|
sigaction(SIGABRT,&sa,0);
|
||||||
|
sigaction(SIGTERM,&sa,0);
|
||||||
|
sigaction(SIGINT,&sa,0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//TODO: This is an ugly workaround. fix it.
|
||||||
|
//TODO: Autodetect public IP.
|
||||||
|
i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"),
|
||||||
|
i2p::util::config::GetArg("-port", 17070));
|
||||||
|
|
||||||
|
i2p::util::HTTPServer httpServer (i2p::util::config::GetArg("-httpport", 7070));
|
||||||
|
|
||||||
|
httpServer.Start ();
|
||||||
i2p::data::netdb.Start ();
|
i2p::data::netdb.Start ();
|
||||||
i2p::transports.Start ();
|
i2p::transports.Start ();
|
||||||
i2p::tunnel::tunnels.Start ();
|
i2p::tunnel::tunnels.Start ();
|
||||||
|
|
||||||
std::this_thread::sleep_for (std::chrono::seconds(10000));
|
while (running)
|
||||||
i2p::tunnel::tunnels.Stop ();
|
{
|
||||||
i2p::transports.Stop ();
|
//TODO Meeh: Find something better to do here.
|
||||||
i2p::data::netdb.Stop ();
|
std::this_thread::sleep_for (std::chrono::seconds(1));
|
||||||
httpServer.Stop ();
|
}
|
||||||
|
LogPrint("Shutdown started.");
|
||||||
|
|
||||||
|
i2p::tunnel::tunnels.Stop ();
|
||||||
|
i2p::transports.Stop ();
|
||||||
|
i2p::data::netdb.Stop ();
|
||||||
|
httpServer.Stop ();
|
||||||
|
|
||||||
|
if (isLogging == 1)
|
||||||
|
{
|
||||||
|
fclose (stdout);
|
||||||
|
}
|
||||||
|
#ifndef _WIN32
|
||||||
|
close(pidFilehandle);
|
||||||
|
unlink(pidfile.c_str());
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,115 +0,0 @@
|
||||||
#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
|
|
274
util.cpp
274
util.cpp
|
@ -1,45 +1,269 @@
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <functional>
|
||||||
|
#include <fstream>
|
||||||
|
#include <set>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/program_options/detail/config_file.hpp>
|
||||||
|
#include <boost/program_options/parsers.hpp>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> mapArgs;
|
|
||||||
|
|
||||||
void ParseArguments(int argc, const char* const argv[])
|
namespace config
|
||||||
{
|
{
|
||||||
mapArgs.clear();
|
std::map<std::string, std::string> mapArgs;
|
||||||
for (int i = 1; i < argc; i++)
|
std::map<std::string, std::vector<std::string> > mapMultiArgs;
|
||||||
{
|
|
||||||
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;
|
void OptionParser(int argc, const char* const argv[])
|
||||||
}
|
{
|
||||||
|
mapArgs.clear();
|
||||||
|
mapMultiArgs.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
boost::to_lower(strKey);
|
||||||
|
if (boost::algorithm::starts_with(strKey, "/"))
|
||||||
|
strKey = "-" + strKey.substr(1);
|
||||||
|
#endif
|
||||||
|
if (strKey[0] != '-')
|
||||||
|
break;
|
||||||
|
|
||||||
|
mapArgs[strKey] = strValue;
|
||||||
|
mapMultiArgs[strKey].push_back(strValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FOREACH(PAIRTYPE(const std::string,std::string)& entry, mapArgs)
|
||||||
|
{
|
||||||
|
std::string name = entry.first;
|
||||||
|
|
||||||
|
// interpret --foo as -foo (as long as both are not set)
|
||||||
|
if (name.find("--") == 0)
|
||||||
|
{
|
||||||
|
std::string singleDash(name.begin()+1, name.end());
|
||||||
|
if (mapArgs.count(singleDash) == 0)
|
||||||
|
mapArgs[singleDash] = entry.second;
|
||||||
|
name = singleDash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetCharArg(const std::string& strArg, const std::string& nDefault)
|
||||||
|
{
|
||||||
|
if (mapArgs.count(strArg))
|
||||||
|
return mapArgs[strArg].c_str();
|
||||||
|
return nDefault.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetArg(const std::string& strArg, const std::string& strDefault)
|
||||||
|
{
|
||||||
|
if (mapArgs.count(strArg))
|
||||||
|
return mapArgs[strArg];
|
||||||
|
return strDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetArg(const std::string& strArg, int nDefault)
|
||||||
|
{
|
||||||
|
if (mapArgs.count(strArg))
|
||||||
|
return atoi(mapArgs[strArg].c_str());
|
||||||
|
return nDefault;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetIntArg(const std::string& strArg, int nDefault)
|
namespace filesystem
|
||||||
{
|
{
|
||||||
if (mapArgs.count(strArg))
|
const boost::filesystem::path &GetDataDir()
|
||||||
return atoi(mapArgs[strArg].c_str());
|
{
|
||||||
return nDefault;
|
static boost::filesystem::path path;
|
||||||
|
|
||||||
|
if (i2p::util::config::mapArgs.count("-datadir")) {
|
||||||
|
path = boost::filesystem::system_complete(i2p::util::config::mapArgs["-datadir"]);
|
||||||
|
} else {
|
||||||
|
path = GetDefaultDataDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!boost::filesystem::exists( path ))
|
||||||
|
{
|
||||||
|
// Create data directory
|
||||||
|
if (!boost::filesystem::create_directory( path ))
|
||||||
|
{
|
||||||
|
LogPrint("Failed to create data directory!");
|
||||||
|
path = "";
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!boost::filesystem::is_directory(path)) {
|
||||||
|
path = GetDefaultDataDir();
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::filesystem::path GetConfigFile()
|
||||||
|
{
|
||||||
|
boost::filesystem::path pathConfigFile(i2p::util::config::GetArg("-conf", "i2p.conf"));
|
||||||
|
if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir() / pathConfigFile;
|
||||||
|
return pathConfigFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet,
|
||||||
|
std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet)
|
||||||
|
{
|
||||||
|
boost::filesystem::ifstream streamConfig(GetConfigFile());
|
||||||
|
if (!streamConfig.good())
|
||||||
|
return; // No i2pd.conf file is OK
|
||||||
|
|
||||||
|
std::set<std::string> setOptions;
|
||||||
|
setOptions.insert("*");
|
||||||
|
|
||||||
|
for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
|
||||||
|
{
|
||||||
|
// Don't overwrite existing settings so command line settings override i2pd.conf
|
||||||
|
std::string strKey = std::string("-") + it->string_key;
|
||||||
|
if (mapSettingsRet.count(strKey) == 0)
|
||||||
|
{
|
||||||
|
mapSettingsRet[strKey] = it->value[0];
|
||||||
|
}
|
||||||
|
mapMultiSettingsRet[strKey].push_back(it->value[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::filesystem::path GetDefaultDataDir()
|
||||||
|
{
|
||||||
|
// Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd
|
||||||
|
// Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd
|
||||||
|
// Mac: ~/Library/Application Support/i2pd
|
||||||
|
// Unix: ~/.i2pd
|
||||||
|
#ifdef WIN32
|
||||||
|
// Windows
|
||||||
|
char localAppData[MAX_PATH];
|
||||||
|
SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData);
|
||||||
|
return boost::filesystem::path(std::string(localAppData) + "\\i2pd");
|
||||||
|
#else
|
||||||
|
boost::filesystem::path pathRet;
|
||||||
|
char* pszHome = getenv("HOME");
|
||||||
|
if (pszHome == NULL || strlen(pszHome) == 0)
|
||||||
|
pathRet = boost::filesystem::path("/");
|
||||||
|
else
|
||||||
|
pathRet = boost::filesystem::path(pszHome);
|
||||||
|
#ifdef MAC_OSX
|
||||||
|
// Mac
|
||||||
|
pathRet /= "Library/Application Support";
|
||||||
|
boost::filesystem::create_directory(pathRet);
|
||||||
|
return pathRet / "i2pd";
|
||||||
|
#else
|
||||||
|
// Unix
|
||||||
|
return pathRet / ".i2pd";
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetStringArg(const std::string& strArg, std::string nDefault)
|
namespace http
|
||||||
{
|
{
|
||||||
if (mapArgs.count(strArg))
|
std::string httpRequest(const std::string& address)
|
||||||
return mapArgs[strArg];
|
{
|
||||||
return nDefault;
|
try
|
||||||
|
{
|
||||||
|
i2p::util::http::url u(address);
|
||||||
|
boost::asio::ip::tcp::iostream site;
|
||||||
|
// please don't uncomment following line because it's not compatible with boost 1.46
|
||||||
|
// 1.46 is default boost for Ubuntu 12.04 LTS
|
||||||
|
//site.expires_from_now (boost::posix_time::seconds(30));
|
||||||
|
site.connect(u.host_, "http");
|
||||||
|
if (site)
|
||||||
|
{
|
||||||
|
// User-Agent is needed to get the server list routerInfo files.
|
||||||
|
site << "GET " << u.path_ << " HTTP/1.0\r\nHost: " << u.host_
|
||||||
|
<< "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\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 (std::getline(site, header) && header != "\r"){}
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << site.rdbuf();
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint ("HTTP response ", status);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint ("Can't connect to ", address);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& ex)
|
||||||
|
{
|
||||||
|
LogPrint ("Failed to download ", address, " : ", ex.what ());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
url::url(const std::string& url_s)
|
||||||
|
{
|
||||||
|
parse(url_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void url::parse(const std::string& url_s)
|
||||||
|
{
|
||||||
|
const std::string prot_end("://");
|
||||||
|
std::string::const_iterator prot_i = search(url_s.begin(), url_s.end(),
|
||||||
|
prot_end.begin(), prot_end.end());
|
||||||
|
protocol_.reserve(distance(url_s.begin(), prot_i));
|
||||||
|
transform(url_s.begin(), prot_i,
|
||||||
|
back_inserter(protocol_),
|
||||||
|
std::ptr_fun<int,int>(tolower)); // protocol is icase
|
||||||
|
if( prot_i == url_s.end() )
|
||||||
|
return;
|
||||||
|
advance(prot_i, prot_end.length());
|
||||||
|
std::string::const_iterator path_i = find(prot_i, url_s.end(), '/');
|
||||||
|
host_.reserve(distance(prot_i, path_i));
|
||||||
|
transform(prot_i, path_i,
|
||||||
|
back_inserter(host_),
|
||||||
|
std::ptr_fun<int,int>(tolower)); // host is icase
|
||||||
|
std::string::const_iterator query_i = find(path_i, url_s.end(), '?');
|
||||||
|
path_.assign(path_i, query_i);
|
||||||
|
if( query_i != url_s.end() )
|
||||||
|
++query_i;
|
||||||
|
query_.assign(query_i, url_s.end());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // Namespace end
|
} // Namespace end
|
||||||
}
|
}
|
||||||
|
|
36
util.h
36
util.h
|
@ -3,15 +3,45 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
|
#define PAIRTYPE(t1, t2) std::pair<t1, t2>
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
extern std::map<std::string, std::string> mapArgs;
|
namespace config
|
||||||
void ParseArguments(int argc, const char* const argv[]);
|
{
|
||||||
int GetIntArg(const std::string& strArg, int nDefault);
|
extern std::map<std::string, std::string> mapArgs;
|
||||||
|
extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
|
||||||
|
void OptionParser(int argc, const char* const argv[]);
|
||||||
|
int GetArg(const std::string& strArg, int nDefault);
|
||||||
|
std::string GetArg(const std::string& strArg, const std::string& strDefault);
|
||||||
|
const char* GetCharArg(const std::string& strArg, const std::string& nDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace filesystem
|
||||||
|
{
|
||||||
|
const boost::filesystem::path &GetDataDir();
|
||||||
|
boost::filesystem::path GetDefaultDataDir();
|
||||||
|
boost::filesystem::path GetConfigFile();
|
||||||
|
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet,
|
||||||
|
std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace http
|
||||||
|
{
|
||||||
|
std::string httpRequest(const std::string& address);
|
||||||
|
struct url {
|
||||||
|
url(const std::string& url_s); // omitted copy, ==, accessors, ...
|
||||||
|
private:
|
||||||
|
void parse(const std::string& url_s);
|
||||||
|
public:
|
||||||
|
std::string protocol_, host_, path_, query_;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue