From 38bc15167c442c22a8fab449ef412bd978f861c9 Mon Sep 17 00:00:00 2001 From: Meeh Date: Thu, 30 Jan 2014 14:28:11 +0100 Subject: [PATCH 01/48] =?UTF-8?q?Fix.=20Thanks=20to=20zzz=20@=C2=A0#i2p-de?= =?UTF-8?q?v?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SSU.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SSU.h b/SSU.h index d8ae7090..3e7ec4f9 100644 --- a/SSU.h +++ b/SSU.h @@ -26,10 +26,11 @@ namespace ssu 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_CREATED = 1; const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2; + const uint8_t PAYLOAD_TYPE_SESSION_DESTROY = 8; const uint8_t PAYLOAD_TYPE_RELAY_REQUEST = 3; const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4; const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5; From 732b17a368e342bd1a6e0344d393f9959a2c8724 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 30 Jan 2014 14:03:11 -0500 Subject: [PATCH 02/48] send SessionCreated message --- SSU.cpp | 38 ++++++++++++++++++++++++++++++++++---- SSU.h | 6 ++++-- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index bfae3d0f..1c7d0155 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -63,7 +63,8 @@ namespace ssu { m_State = eSessionStateRequestReceived; LogPrint ("Session request received"); - SendSessionCreated (senderEndpoint); + m_RemoteEndpoint = senderEndpoint; + SendSessionCreated (buf + sizeof (SSUHeader)); } } @@ -102,7 +103,7 @@ namespace ssu 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) @@ -110,11 +111,40 @@ namespace ssu 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 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) = m_RemoteEndpoint.address ().to_v4 ().to_ulong (); // network bytes order already + 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) = 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); } @@ -209,7 +239,7 @@ namespace ssu } SSUServer::SSUServer (boost::asio::io_service& service, int port): - m_Socket (service, boost::asio::ip::udp::endpoint (boost::asio::ip::udp::v4 (), port)) + m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint) { } diff --git a/SSU.h b/SSU.h index 3e7ec4f9..6b2d108a 100644 --- a/SSU.h +++ b/SSU.h @@ -68,7 +68,7 @@ namespace ssu void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void SendSessionRequest (); void ProcessSessionCreated (uint8_t * buf, size_t len); - void SendSessionCreated (const boost::asio::ip::udp::endpoint& senderEndpoint); + void SendSessionCreated (const uint8_t * x); bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len); void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); @@ -95,7 +95,8 @@ namespace ssu void Start (); void Stop (); SSUSession * GetSession (i2p::data::RouterInfo * router); - + + 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); private: @@ -105,6 +106,7 @@ namespace ssu private: + boost::asio::ip::udp::endpoint m_Endpoint; boost::asio::ip::udp::socket m_Socket; boost::asio::ip::udp::endpoint m_SenderEndpoint; uint8_t m_ReceiveBuffer[2*SSU_MTU]; From 633c9becd919d8d8ac73a80fd04d9de081b6eea1 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 01:39:16 +0100 Subject: [PATCH 03/48] Adding more to the option parser. Adding instruction on how to test it. --- README.md | 30 ++++++++++++++++++++++++++++++ i2p.cpp | 5 ++++- util.cpp | 8 ++++---- util.h | 3 ++- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ab64cb4d..32eec060 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,33 @@ Requires gcc 4.6 and higher, boost 1.46 and higher, crypto++ on Windows Requires msvs2013, boost 1.46 and higher, crypto++ + + +Testing +------- + +First, build it. + +$ cd i2pd +$ make + +Now, copy your netDb folder from your Java I2P config dir. (The one with r0, r1, r2, ... folders in it) to the source folder where your i2p binary is. + +Next, find out your public ip. (find it for example at http://www.whatismyip.com/) + +Then, run it with: + +$ ./i2p --host=YOUR_PUBLIC_IP + + +Other options: +--port= - The port to listen on +--httpport= - The http port to listen on + + +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 + diff --git a/i2p.cpp b/i2p.cpp index 67408fa6..5c0bd378 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -14,7 +14,7 @@ int main( int argc, char* argv[] ) { - i2p::util::ParseArguments(argc,argv); + i2p::util::OptionParser(argc,argv); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); @@ -22,6 +22,9 @@ int main( int argc, char* argv[] ) setlocale(LC_ALL, "Russian"); #endif + //TODO: This is an ugly workaround. fix it. + //TODO: Autodetect public IP. + i2p::context.OverrideNTCPAddress(i2p::util::GetCharArg("--host", "127.0.0.1"), i2p::util::GetIntArg("--port", 17070)); int httpport = i2p::util::GetIntArg("--httpport", 7070); i2p::util::HTTPServer httpServer (httpport); diff --git a/util.cpp b/util.cpp index 1f000f50..676fddd1 100644 --- a/util.cpp +++ b/util.cpp @@ -6,7 +6,7 @@ namespace util { std::map mapArgs; -void ParseArguments(int argc, const char* const argv[]) +void OptionParser(int argc, const char* const argv[]) { mapArgs.clear(); for (int i = 1; i < argc; i++) @@ -33,11 +33,11 @@ int GetIntArg(const std::string& strArg, int nDefault) return nDefault; } -std::string GetStringArg(const std::string& strArg, std::string nDefault) +const char* GetCharArg(const std::string& strArg, const std::string& nDefault) { if (mapArgs.count(strArg)) - return mapArgs[strArg]; - return nDefault; + return mapArgs[strArg].c_str(); + return nDefault.c_str(); } diff --git a/util.h b/util.h index ef015ded..fb3597e6 100644 --- a/util.h +++ b/util.h @@ -9,8 +9,9 @@ namespace i2p namespace util { extern std::map mapArgs; - void ParseArguments(int argc, const char* const argv[]); + void OptionParser(int argc, const char* const argv[]); int GetIntArg(const std::string& strArg, int nDefault); + const char* GetCharArg(const std::string& strArg, const std::string& nDefault); } } From e6ccffcf77d65978d8350817a26ca0904b4e8ad0 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 01:42:27 +0100 Subject: [PATCH 04/48] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 32eec060..3117f52a 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ Testing First, build it. -$ cd i2pd -$ make +* $ cd i2pd +* $ make Now, copy your netDb folder from your Java I2P config dir. (The one with r0, r1, r2, ... folders in it) to the source folder where your i2p binary is. @@ -28,8 +28,8 @@ $ ./i2p --host=YOUR_PUBLIC_IP Other options: ---port= - The port to listen on ---httpport= - The http port to listen on +* --port= - The port to listen on +* --httpport= - The http port to listen on To visit an I2P page, you need to find the b32 address of your destination. From b4e2c7ee87e8987ec63fdd4f3e960d478b1d124b Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 02:49:06 +0100 Subject: [PATCH 05/48] Updating Makefile to collect build objects in a folder --- .gitignore | 2 +- Makefile | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 2cb9ea10..0e609a70 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # i2pd -*.o +obj/*.o router.info router.keys i2p diff --git a/Makefile b/Makefile index abe4238d..5a3e6336 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,28 @@ CC = g++ CFLAGS = -g -Wall -std=c++0x -OBJECTS = i2p.o base64.o NTCPSession.o RouterInfo.o Transports.o RouterContext.o \ - NetDb.o LeaseSet.o Tunnel.o TunnelEndpoint.o TunnelGateway.o TransitTunnel.o \ - I2NPProtocol.o Log.o Garlic.o HTTPServer.o Streaming.o Identity.o SSU.o util.o +OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \ + obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.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 INCFLAGS = LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lpthread LIBS = all: i2p -i2p: $(OBJECTS) - $(CC) -o i2p $(OBJECTS) $(LDFLAGS) $(LIBS) +i2p: $(OBJECTS:obj/%=obj/%) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) .SUFFIXES: .SUFFIXES: .c .cc .C .cpp .o -.cpp.o : - $(CC) -o $@ -c $(CFLAGS) $< $(INCFLAGS) +obj/%.o : %.cpp + mkdir -p obj + $(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) clean: - rm -f *.o + rm -fr obj .PHONY: all .PHONY: clean From e6e74efc26ec381d6fe49ffa57e532c939a570c5 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 30 Jan 2014 22:23:13 -0500 Subject: [PATCH 06/48] call mkdir only once --- Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 5a3e6336..370b3a0a 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ INCFLAGS = LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lpthread LIBS = -all: i2p +all: obj i2p i2p: $(OBJECTS:obj/%=obj/%) $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) @@ -18,11 +18,14 @@ i2p: $(OBJECTS:obj/%=obj/%) .SUFFIXES: .c .cc .C .cpp .o obj/%.o : %.cpp - mkdir -p obj $(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) +obj: + mkdir -p obj + clean: - rm -fr obj + rm -fr obj i2p .PHONY: all .PHONY: clean + From 86355cfe09278ff158bf45192451da0017dd72b2 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 07:22:11 +0100 Subject: [PATCH 07/48] Adding reseed support. v1, only http so far. --- Makefile | 4 +-- NetDb.cpp | 56 +++++++++----------------------- NetDb.h | 3 +- Reseed.cpp | 70 ++++++++++++++++++++++++++++++++++++++++ Reseed.h | 28 ++++++++++++++++ util.cpp | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ util.h | 12 ++++++- 7 files changed, 223 insertions(+), 45 deletions(-) create mode 100644 Reseed.cpp create mode 100644 Reseed.h diff --git a/Makefile b/Makefile index 5a3e6336..5c2e61fb 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,9 @@ CFLAGS = -g -Wall -std=c++0x OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \ obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.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/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o 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 -lpthread LIBS = all: i2p diff --git a/NetDb.cpp b/NetDb.cpp index 278e8286..4d4ce103 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -13,6 +13,7 @@ #include "RouterContext.h" #include "Garlic.h" #include "NetDb.h" +#include "Reseed.h" namespace i2p { @@ -207,12 +208,23 @@ namespace data void NetDb::Load (const char * directory) { + Load(directory, false); + } + + void NetDb::Load (const char * directory, bool reseed) + { + i2p::data::Reseeder *reseeder = new i2p::data::Reseeder(); boost::filesystem::path p (directory); if (!boost::filesystem::exists (p)) { if (!CreateNetDb(directory)) return; + reseeder->reseedNow(); + } + if (reseed) + { + reseeder->reseedNow(); + m_reseedRetries++; } - // TODO: Reseed if needed. int numRouters = 0; boost::filesystem::directory_iterator end; for (boost::filesystem::directory_iterator it (p); it != end; ++it) @@ -232,6 +244,8 @@ namespace data } } LogPrint (numRouters, " routers loaded"); + if (numRouters < 100 && m_reseedRetries < 10) + Load(directory, true); // Reseed } void NetDb::SaveUpdated (const char * directory) @@ -601,45 +615,5 @@ namespace data return r; } - //TODO: Move to reseed. - //TODO: Implement v1 & v2 reseeding. Lightweight zip library is needed for v2. - // orignal: zip is part of crypto++, see implementation of DatabaseStoreMsg - //TODO: Implement SU3, utils. - void NetDb::DownloadRouterInfo (const std::string& address, const std::string& filename) - { - try - { - boost::asio::ip::tcp::iostream site(address, "http"); - if (!site) - { - //site.expires_from_now (boost::posix_time::seconds (10)); // wait for 10 seconds - site << "GET " << filename << "HTTP/1.0\nHost: " << address << "\nAccept: */*\nConnection: close\n\n"; - // read response - std::string version, statusMessage; - site >> version; // HTTP version - int status; - site >> status; // status - std::getline (site, statusMessage); - if (status == 200) // OK - { - std::string header; - while (header != "\n") - std::getline (site, header); - // read content - std::stringstream ss; - ss << site.rdbuf(); - AddRouterInfo ((uint8_t *)ss.str ().c_str (), ss.str ().size ()); - } - else - LogPrint ("HTTP response ", status); - } - else - LogPrint ("Can't connect to ", address); - } - catch (std::exception& ex) - { - LogPrint ("Failed to download ", filename, " : ", ex.what ()); - } - } } } diff --git a/NetDb.h b/NetDb.h index 1397e9e4..ddf50d06 100644 --- a/NetDb.h +++ b/NetDb.h @@ -78,8 +78,8 @@ namespace data bool CreateNetDb(const char * directory); void Load (const char * directory); + void Load (const char * directory, bool reseed); void SaveUpdated (const char * directory); - void DownloadRouterInfo (const std::string& address, const std::string& filename); // for reseed void Run (); // exploratory thread void Explore (); const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set& excluded) const; @@ -95,6 +95,7 @@ namespace data std::map m_RequestedDestinations; bool m_IsRunning; + int m_reseedRetries = 0; std::thread * m_Thread; i2p::util::Queue m_Queue; // of I2NPDatabaseStoreMsg }; diff --git a/Reseed.cpp b/Reseed.cpp new file mode 100644 index 00000000..cc61e4ef --- /dev/null +++ b/Reseed.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include "Reseed.h" +#include "Log.h" +#include "util.h" + + +namespace i2p +{ +namespace data +{ + + 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; + std::string name; + std::string routerInfo; + std::string tmpUrl; + std::string filename; + while (i != j) + { + name = *i++; + LogPrint("Downloading ", name); + tmpUrl = reseedHost; + tmpUrl.append(name); + routerInfo = i2p::util::http::httpRequest(tmpUrl); + filename = "netDb/r"; + filename += name.at(11); + filename.append("/"); + 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; + } + +} +} + diff --git a/Reseed.h b/Reseed.h new file mode 100644 index 00000000..ac5a7cd7 --- /dev/null +++ b/Reseed.h @@ -0,0 +1,28 @@ +#ifndef RESEED_H +#define RESEED_H + +#include +#include + +namespace i2p +{ +namespace data +{ + + class Reseeder + { + public: + Reseeder(); + ~Reseeder(); + bool reseedNow(); + private: + std::vector httpReseedHostList = { + "http://193.150.121.66/netDb/", + "http://netdb.i2p2.no/" + }; + }; + +} +} + +#endif \ No newline at end of file diff --git a/util.cpp b/util.cpp index 676fddd1..a101dfe4 100644 --- a/util.cpp +++ b/util.cpp @@ -1,4 +1,11 @@ +#include +#include +#include +#include +#include +#include #include "util.h" +#include "Log.h" namespace i2p { @@ -40,6 +47,94 @@ const char* GetCharArg(const std::string& strArg, const std::string& nDefault) return nDefault.c_str(); } +namespace http +{ +//const std::string& filename +//AddRouterInfo ((uint8_t *)ss.str ().c_str (), ss.str ().size ()); + //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. + std::string httpRequest(const std::string& address) + { + try + { + i2p::util::http::url u(address); + boost::asio::ip::tcp::iostream site; + site.expires_from_now (boost::posix_time::seconds(30)); + site.connect(u.host_, "http"); + if (site) + { + //site.expires_from_now (boost::posix_time::seconds (10)); // wait for 10 seconds + // 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(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(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 } diff --git a/util.h b/util.h index fb3597e6..7643e0d0 100644 --- a/util.h +++ b/util.h @@ -12,7 +12,17 @@ namespace util void OptionParser(int argc, const char* const argv[]); int GetIntArg(const std::string& strArg, int nDefault); const char* GetCharArg(const std::string& strArg, const std::string& nDefault); - + 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_; + }; + } } } From 83bd3c21ca6fc92d3d87567113f226a811effd56 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 07:31:06 +0100 Subject: [PATCH 08/48] Adding more reseed hosts Ignore zip files --- Reseed.cpp | 4 ++++ Reseed.h | 10 +++++++++- util.cpp | 6 +----- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Reseed.cpp b/Reseed.cpp index cc61e4ef..05825f6a 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -40,9 +40,13 @@ namespace data std::string routerInfo; std::string tmpUrl; std::string filename; + std::string ignoreFileSuffix = ".zip"; while (i != j) { + //TODO: Ugly code, try to clean up. name = *i++; + if (name.find(ignoreFileSuffix)!=std::string::npos) + continue; LogPrint("Downloading ", name); tmpUrl = reseedHost; tmpUrl.append(name); diff --git a/Reseed.h b/Reseed.h index ac5a7cd7..96ce9c55 100644 --- a/Reseed.h +++ b/Reseed.h @@ -18,7 +18,15 @@ namespace data private: std::vector httpReseedHostList = { "http://193.150.121.66/netDb/", - "http://netdb.i2p2.no/" + "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" }; }; diff --git a/util.cpp b/util.cpp index a101dfe4..5834e2ab 100644 --- a/util.cpp +++ b/util.cpp @@ -49,11 +49,7 @@ const char* GetCharArg(const std::string& strArg, const std::string& nDefault) namespace http { -//const std::string& filename -//AddRouterInfo ((uint8_t *)ss.str ().c_str (), ss.str ().size ()); - //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 v2 reseeding. Lightweight zip library is needed. //TODO: Implement SU3, utils. std::string httpRequest(const std::string& address) { From 9415a49fbd618ad0d770022628a5ac6784ddbb17 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 07:35:21 +0100 Subject: [PATCH 09/48] documentation update --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 3117f52a..dc4e0a8c 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,13 @@ First, build it. * $ cd i2pd * $ make -Now, copy your netDb folder from your Java I2P config dir. (The one with r0, r1, r2, ... folders in it) to the source folder where your i2p binary is. - 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. Other options: * --port= - The port to listen on From 849ab03e1c261d96c23db1ca094aa2ab0af984a4 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 07:43:56 +0100 Subject: [PATCH 10/48] Cleanup and final comments --- Reseed.cpp | 12 ++++++------ util.cpp | 3 --- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Reseed.cpp b/Reseed.cpp index 05825f6a..1442b1b4 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include "Reseed.h" #include "Log.h" @@ -11,7 +10,8 @@ namespace i2p { namespace data { - + //TODO: Implement v2 reseeding. Lightweight zip library is needed. + //TODO: Implement SU3, utils. Reseeder::Reseeder() { } @@ -32,10 +32,11 @@ namespace data LogPrint("Reseed failed"); return false; } - boost::regex e("<\\s*A\\s+[^>]*href\\s*=\\s*\"([^\"]*)\"", - boost::regex::normal | boost::regbase::icase); + 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; @@ -43,7 +44,6 @@ namespace data std::string ignoreFileSuffix = ".zip"; while (i != j) { - //TODO: Ugly code, try to clean up. name = *i++; if (name.find(ignoreFileSuffix)!=std::string::npos) continue; @@ -52,7 +52,7 @@ namespace data tmpUrl.append(name); routerInfo = i2p::util::http::httpRequest(tmpUrl); filename = "netDb/r"; - filename += name.at(11); + filename += name.at(11); // first char in id filename.append("/"); filename.append(name.c_str()); std::ofstream outfile (filename, std::ios::binary); diff --git a/util.cpp b/util.cpp index 5834e2ab..a33414ac 100644 --- a/util.cpp +++ b/util.cpp @@ -49,8 +49,6 @@ const char* GetCharArg(const std::string& strArg, const std::string& nDefault) namespace http { - //TODO: Implement v2 reseeding. Lightweight zip library is needed. - //TODO: Implement SU3, utils. std::string httpRequest(const std::string& address) { try @@ -61,7 +59,6 @@ namespace http site.connect(u.host_, "http"); if (site) { - //site.expires_from_now (boost::posix_time::seconds (10)); // wait for 10 seconds // 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"; From 8d98722b4652c846107aac705764b65e72dfbc1e Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 31 Jan 2014 07:32:34 -0500 Subject: [PATCH 11/48] fixed compilation error in gcc 4.6 --- NetDb.cpp | 6 +++--- NetDb.h | 2 +- Reseed.cpp | 14 ++++++++++++++ Reseed.h | 13 ------------- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 4d4ce103..5f76a8c1 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -45,7 +45,7 @@ namespace data NetDb netdb; - NetDb::NetDb (): m_IsRunning (false), m_Thread (0) + NetDb::NetDb (): m_IsRunning (false), m_ReseedRetries (0), m_Thread (0) { } @@ -223,7 +223,7 @@ namespace data if (reseed) { reseeder->reseedNow(); - m_reseedRetries++; + m_ReseedRetries++; } int numRouters = 0; boost::filesystem::directory_iterator end; @@ -244,7 +244,7 @@ namespace data } } LogPrint (numRouters, " routers loaded"); - if (numRouters < 100 && m_reseedRetries < 10) + if (numRouters < 100 && m_ReseedRetries < 10) Load(directory, true); // Reseed } diff --git a/NetDb.h b/NetDb.h index ddf50d06..432036dc 100644 --- a/NetDb.h +++ b/NetDb.h @@ -95,7 +95,7 @@ namespace data std::map m_RequestedDestinations; bool m_IsRunning; - int m_reseedRetries = 0; + int m_ReseedRetries; std::thread * m_Thread; i2p::util::Queue m_Queue; // of I2NPDatabaseStoreMsg }; diff --git a/Reseed.cpp b/Reseed.cpp index 1442b1b4..540caa15 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -10,6 +10,20 @@ namespace i2p { namespace data { + + static std::vector 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() diff --git a/Reseed.h b/Reseed.h index 96ce9c55..3b07d840 100644 --- a/Reseed.h +++ b/Reseed.h @@ -15,19 +15,6 @@ namespace data Reseeder(); ~Reseeder(); bool reseedNow(); - private: - std::vector 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" - }; }; } From 0e5bbfa21c6e63b7a842ac91471049f132ef8459 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 31 Jan 2014 13:08:33 -0500 Subject: [PATCH 12/48] avoid unnececssary recusion --- NetDb.cpp | 30 +++++++++++++++--------------- NetDb.h | 1 - 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 5f76a8c1..49c37562 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -63,6 +63,13 @@ namespace data void NetDb::Start () { Load ("netDb"); + while (m_RouterInfos.size () < 100 && m_ReseedRetries < 10) + { + Reseeder reseeder; + reseeder.reseedNow(); + m_ReseedRetries++; + Load ("netDb"); + } m_Thread = new std::thread (std::bind (&NetDb::Run, this)); } @@ -205,26 +212,21 @@ namespace data } return true; } - + void NetDb::Load (const char * directory) { - Load(directory, false); - } - - void NetDb::Load (const char * directory, bool reseed) - { - i2p::data::Reseeder *reseeder = new i2p::data::Reseeder(); boost::filesystem::path p (directory); if (!boost::filesystem::exists (p)) { + // seems netDb doesn't exist yet if (!CreateNetDb(directory)) return; - reseeder->reseedNow(); - } - if (reseed) - { - reseeder->reseedNow(); - m_ReseedRetries++; } + // 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; boost::filesystem::directory_iterator end; for (boost::filesystem::directory_iterator it (p); it != end; ++it) @@ -244,8 +246,6 @@ namespace data } } LogPrint (numRouters, " routers loaded"); - if (numRouters < 100 && m_ReseedRetries < 10) - Load(directory, true); // Reseed } void NetDb::SaveUpdated (const char * directory) diff --git a/NetDb.h b/NetDb.h index 432036dc..3fb6ad10 100644 --- a/NetDb.h +++ b/NetDb.h @@ -78,7 +78,6 @@ namespace data bool CreateNetDb(const char * directory); void Load (const char * directory); - void Load (const char * directory, bool reseed); void SaveUpdated (const char * directory); void Run (); // exploratory thread void Explore (); From d95b4befaa66b8047398075391e3591b1e2a9e84 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 04:09:55 +0100 Subject: [PATCH 13/48] Adding support for config file Example: -port=17070 --port=17070 cat /home/$USER/.i2pd/i2p.conf port=17070 --- Makefile | 2 +- i2p.cpp | 21 +++++- util.cpp | 214 +++++++++++++++++++++++++++++++++++++++++++------------ util.h | 24 +++++-- 4 files changed, 206 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index 240e4a3b..b5739c46 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transpor 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 = -LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lpthread +LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LIBS = all: obj i2p diff --git a/i2p.cpp b/i2p.cpp index 5c0bd378..82a69671 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "Log.h" #include "base64.h" #include "Transports.h" @@ -14,7 +15,7 @@ int main( int argc, char* argv[] ) { - i2p::util::OptionParser(argc,argv); + i2p::util::config::OptionParser(argc,argv); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); @@ -22,10 +23,24 @@ int main( int argc, char* argv[] ) setlocale(LC_ALL, "Russian"); #endif + LogPrint("\n\n\n\ni2pd starting\n"); + LogPrint("default data directory: ", i2p::util::filesystem::GetDefaultDataDir().string()); + if (!boost::filesystem::exists( i2p::util::filesystem::GetDefaultDataDir() )) + { + // Create data directory + if (!boost::filesystem::create_directory( i2p::util::filesystem::GetDefaultDataDir() )) + { + LogPrint("Failed to create data directory, exiting! :("); + return -1; + } + } + i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); + //TODO: This is an ugly workaround. fix it. //TODO: Autodetect public IP. - i2p::context.OverrideNTCPAddress(i2p::util::GetCharArg("--host", "127.0.0.1"), i2p::util::GetIntArg("--port", 17070)); - int httpport = i2p::util::GetIntArg("--httpport", 7070); + i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), + i2p::util::config::GetArg("-port", 17070)); + int httpport = i2p::util::config::GetArg("-httpport", 7070); i2p::util::HTTPServer httpServer (httpport); diff --git a/util.cpp b/util.cpp index a33414ac..ff013035 100644 --- a/util.cpp +++ b/util.cpp @@ -3,7 +3,13 @@ #include #include #include +#include #include +#include +#include +#include +#include +#include #include "util.h" #include "Log.h" @@ -11,40 +17,154 @@ namespace i2p { namespace util { -std::map mapArgs; -void OptionParser(int argc, const char* const argv[]) +namespace config { - mapArgs.clear(); - for (int i = 1; i < argc; i++) - { - std::string strKey (argv[i]); - std::string strValue; - size_t has_data = strKey.find('='); - if (has_data != std::string::npos) - { - strValue = strKey.substr(has_data+1); - strKey = strKey.substr(0, has_data); - } - if (strKey[0] != '-') - break; + std::map mapArgs; + std::map > mapMultiArgs; - 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)) - return atoi(mapArgs[strArg].c_str()); - return nDefault; -} + const boost::filesystem::path &GetDataDir(bool fNetSpecific) + { -const char* GetCharArg(const std::string& strArg, const std::string& nDefault) -{ - if (mapArgs.count(strArg)) - return mapArgs[strArg].c_str(); - return nDefault.c_str(); + static boost::filesystem::path path; + + if (config::mapArgs.count("--datadir")) { + path = boost::filesystem::system_complete(config::mapArgs["--datadir"]); + if (!boost::filesystem::is_directory(path)) { + path = ""; + return path; + } + } else { + path = GetDefaultDataDir(); + } + + boost::filesystem::create_directory(path); + + return path; + } + + boost::filesystem::path GetConfigFile() + { + boost::filesystem::path pathConfigFile(i2p::util::config::GetArg("-conf", "i2p.conf")); + if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile; + return pathConfigFile; + } + + void ReadConfigFile(std::map& mapSettingsRet, + std::map >& mapMultiSettingsRet) + { + boost::filesystem::ifstream streamConfig(GetConfigFile()); + if (!streamConfig.good()) + return; // No i2pd.conf file is OK + + std::set 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 + return GetSpecialFolderPath(CSIDL_APPDATA) / "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 + } } namespace http @@ -102,26 +222,26 @@ namespace http 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(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(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()); + 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(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(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()); } } diff --git a/util.h b/util.h index 7643e0d0..7f22e3f1 100644 --- a/util.h +++ b/util.h @@ -4,14 +4,30 @@ #include #include +#define PAIRTYPE(t1, t2) std::pair + namespace i2p { namespace util { - extern std::map mapArgs; - void OptionParser(int argc, const char* const argv[]); - int GetIntArg(const std::string& strArg, int nDefault); - const char* GetCharArg(const std::string& strArg, const std::string& nDefault); + namespace config + { + extern std::map mapArgs; + extern std::map > 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 + { + boost::filesystem::path GetDefaultDataDir(); + boost::filesystem::path GetConfigFile(); + void ReadConfigFile(std::map& mapSettingsRet, + std::map >& mapMultiSettingsRet); + } + namespace http { std::string httpRequest(const std::string& address); From 56f1f627ef8af1ba1592561ae42abba68d090c0f Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 04:15:19 +0100 Subject: [PATCH 14/48] use single dash to query options --- util.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util.cpp b/util.cpp index ff013035..2da8fdb5 100644 --- a/util.cpp +++ b/util.cpp @@ -94,8 +94,8 @@ namespace filesystem static boost::filesystem::path path; - if (config::mapArgs.count("--datadir")) { - path = boost::filesystem::system_complete(config::mapArgs["--datadir"]); + if (config::mapArgs.count("-datadir")) { + path = boost::filesystem::system_complete(config::mapArgs["-datadir"]); if (!boost::filesystem::is_directory(path)) { path = ""; return path; From 2fd31c6c8d77637a828c09b2d0ac3e9ba3ccbfa6 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 04:51:58 +0100 Subject: [PATCH 15/48] Custom datadir + cleanup --- i2p.cpp | 11 +---------- util.cpp | 27 +++++++++++++++++---------- util.h | 1 + 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/i2p.cpp b/i2p.cpp index 82a69671..aed38cd0 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -24,16 +24,7 @@ int main( int argc, char* argv[] ) #endif LogPrint("\n\n\n\ni2pd starting\n"); - LogPrint("default data directory: ", i2p::util::filesystem::GetDefaultDataDir().string()); - if (!boost::filesystem::exists( i2p::util::filesystem::GetDefaultDataDir() )) - { - // Create data directory - if (!boost::filesystem::create_directory( i2p::util::filesystem::GetDefaultDataDir() )) - { - LogPrint("Failed to create data directory, exiting! :("); - return -1; - } - } + LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string()); i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); //TODO: This is an ugly workaround. fix it. diff --git a/util.cpp b/util.cpp index 2da8fdb5..1c64cc75 100644 --- a/util.cpp +++ b/util.cpp @@ -89,30 +89,37 @@ namespace config namespace filesystem { - const boost::filesystem::path &GetDataDir(bool fNetSpecific) + const boost::filesystem::path &GetDataDir() { static boost::filesystem::path path; - if (config::mapArgs.count("-datadir")) { - path = boost::filesystem::system_complete(config::mapArgs["-datadir"]); - if (!boost::filesystem::is_directory(path)) { - path = ""; - return path; - } + if (i2p::util::config::mapArgs.count("-datadir")) { + path = boost::filesystem::system_complete(i2p::util::config::mapArgs["-datadir"]); } else { path = GetDefaultDataDir(); } - boost::filesystem::create_directory(path); - + if (!boost::filesystem::exists( path )) + { + // Create data directory + if (!boost::filesystem::create_directory( path )) + { + LogPrint("Failed to create data directory!"); + return ""; + } + } + if (!boost::filesystem::is_directory(path)) { + path = GetDefaultDataDir(); + } + LogPrint("Debug: ",path.string()); return path; } boost::filesystem::path GetConfigFile() { boost::filesystem::path pathConfigFile(i2p::util::config::GetArg("-conf", "i2p.conf")); - if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile; + if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir() / pathConfigFile; return pathConfigFile; } diff --git a/util.h b/util.h index 7f22e3f1..7090294f 100644 --- a/util.h +++ b/util.h @@ -22,6 +22,7 @@ namespace util namespace filesystem { + const boost::filesystem::path &GetDataDir(); boost::filesystem::path GetDefaultDataDir(); boost::filesystem::path GetConfigFile(); void ReadConfigFile(std::map& mapSettingsRet, From ef9801f704ce012cdfacf00a3175dc87cc649a77 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 05:25:59 +0100 Subject: [PATCH 16/48] Remove debug --- util.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/util.cpp b/util.cpp index 1c64cc75..e988427c 100644 --- a/util.cpp +++ b/util.cpp @@ -112,7 +112,6 @@ namespace filesystem if (!boost::filesystem::is_directory(path)) { path = GetDefaultDataDir(); } - LogPrint("Debug: ",path.string()); return path; } From f639f971b2d673a367cdb3ff27624899b8bffef2 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 14:28:30 +0100 Subject: [PATCH 17/48] Should fix compilation error on some systems --- util.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util.h b/util.h index 7090294f..519e51b3 100644 --- a/util.h +++ b/util.h @@ -3,6 +3,8 @@ #include #include +#include +#include #define PAIRTYPE(t1, t2) std::pair From bf2e8d23507266e4612edb755a0f310aada83ec3 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Feb 2014 09:06:28 -0500 Subject: [PATCH 18/48] fixed HMAC calculation. Tested and verified --- hmac.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hmac.h b/hmac.h index df35a142..6e9c042b 100644 --- a/hmac.h +++ b/hmac.h @@ -18,7 +18,6 @@ namespace crypto // digest is 16 bytes // block size is 64 bytes { - size_t totalLen = len + 64 + 32; uint8_t buf[2048]; // ikeypad ((uint64_t *)buf)[0] = ((uint64_t *)key)[0] ^ IPAD; @@ -47,10 +46,10 @@ namespace crypto // copy first hash after okeypad memcpy (buf + 64, hash, 16); // fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P) - memset (buf + 72, 0, 16); + memset (buf + 80, 0, 16); // calculate digest - CryptoPP::Weak1::MD5().CalculateDigest (digest, buf, totalLen); + CryptoPP::Weak1::MD5().CalculateDigest (digest, buf, 96); } } } From ca1e1c48967a991c276cff32634c817c25be7764 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Feb 2014 09:16:50 -0500 Subject: [PATCH 19/48] fixed compilation error and potentil memory corruption --- util.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/util.cpp b/util.cpp index e988427c..88a1f7c8 100644 --- a/util.cpp +++ b/util.cpp @@ -91,7 +91,6 @@ namespace filesystem { const boost::filesystem::path &GetDataDir() { - static boost::filesystem::path path; if (i2p::util::config::mapArgs.count("-datadir")) { @@ -106,7 +105,8 @@ namespace filesystem if (!boost::filesystem::create_directory( path )) { LogPrint("Failed to create data directory!"); - return ""; + path = ""; + return path; } } if (!boost::filesystem::is_directory(path)) { @@ -181,7 +181,9 @@ namespace http { i2p::util::http::url u(address); boost::asio::ip::tcp::iostream site; - site.expires_from_now (boost::posix_time::seconds(30)); + // 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) { From d87a79b226801eb4758be60ab06d1612860285a9 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 16:10:15 +0100 Subject: [PATCH 20/48] Load netDb from data directory --- NetDb.cpp | 29 +++++++++++++++++++---------- NetDb.h | 2 +- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 49c37562..41aa7c4f 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -14,6 +14,7 @@ #include "Garlic.h" #include "NetDb.h" #include "Reseed.h" +#include "util.h" namespace i2p { @@ -62,13 +63,21 @@ namespace data void NetDb::Start () { - Load ("netDb"); +#ifndef _WIN32 + Load ("/netDb"); +#else + Load ("\\netDb"); +#endif while (m_RouterInfos.size () < 100 && m_ReseedRetries < 10) { Reseeder reseeder; reseeder.reseedNow(); m_ReseedRetries++; - Load ("netDb"); +#ifndef _WIN32 + Load ("/netDb"); +#else + Load ("\\netDb"); +#endif } m_Thread = new std::thread (std::bind (&NetDb::Run, this)); } @@ -188,13 +197,12 @@ namespace data } // 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, " doesn't exist, trying to create it."); - if (!boost::filesystem::create_directory (p)) + LogPrint (directory.string(), " doesn't exist, trying to create it."); + if (!boost::filesystem::create_directory (directory)) { - LogPrint("Failed to create directory ", directory); + LogPrint("Failed to create directory ", directory.string()); return false; } @@ -208,18 +216,19 @@ namespace data #else suffix = std::string ("\\r") + chars[i]; #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; } 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)) { // seems netDb doesn't exist yet - if (!CreateNetDb(directory)) return; + if (!CreateNetDb(p)) return; } // make sure we cleanup netDb from previous attempts for (auto r: m_RouterInfos) diff --git a/NetDb.h b/NetDb.h index 3fb6ad10..7988276a 100644 --- a/NetDb.h +++ b/NetDb.h @@ -76,7 +76,7 @@ namespace data private: - bool CreateNetDb(const char * directory); + bool CreateNetDb(boost::filesystem::path directory); void Load (const char * directory); void SaveUpdated (const char * directory); void Run (); // exploratory thread From 8963c0b3090837fdfae6e4600860f525d908861b Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Feb 2014 15:57:46 -0500 Subject: [PATCH 21/48] save new RouterInfos to ~/.i2pd --- NetDb.cpp | 40 +++++++++++++++++++++------------------- NetDb.h | 3 +++ 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 41aa7c4f..01234ad7 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include "base64.h" #include "Log.h" @@ -20,7 +19,6 @@ namespace i2p { namespace data { - I2NPMessage * RequestedDestination::CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel) { @@ -43,7 +41,12 @@ namespace data m_LastReplyTunnel = nullptr; return msg; } - + +#ifndef _WIN32 + const char NetDb::m_NetDbPath[] = "/netDb"; +#else + const char NetDb::m_NetDbPath[] = "\\netDb"; +#endif NetDb netdb; NetDb::NetDb (): m_IsRunning (false), m_ReseedRetries (0), m_Thread (0) @@ -62,22 +65,14 @@ namespace data } void NetDb::Start () - { -#ifndef _WIN32 - Load ("/netDb"); -#else - Load ("\\netDb"); -#endif + { + Load (m_NetDbPath); while (m_RouterInfos.size () < 100 && m_ReseedRetries < 10) { Reseeder reseeder; reseeder.reseedNow(); m_ReseedRetries++; -#ifndef _WIN32 - Load ("/netDb"); -#else - Load ("\\netDb"); -#endif + Load (m_NetDbPath); } m_Thread = new std::thread (std::bind (&NetDb::Run, this)); } @@ -128,7 +123,7 @@ namespace data if (ts - lastTs >= 60) // save routers every minute { if (lastTs) - SaveUpdated ("netDb"); + SaveUpdated (m_NetDbPath); lastTs = ts; } } @@ -270,7 +265,14 @@ namespace data #endif 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; auto total = m_RouterInfos.size (); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); @@ -278,7 +280,7 @@ namespace data { 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 ()); it.second->SetUpdated (false); count++; @@ -294,9 +296,9 @@ namespace data 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++; } } diff --git a/NetDb.h b/NetDb.h index 7988276a..bcf1f23c 100644 --- a/NetDb.h +++ b/NetDb.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "Queue.h" #include "I2NPProtocol.h" #include "RouterInfo.h" @@ -97,6 +98,8 @@ namespace data int m_ReseedRetries; std::thread * m_Thread; i2p::util::Queue m_Queue; // of I2NPDatabaseStoreMsg + + static const char m_NetDbPath[]; }; extern NetDb netdb; From 499a7a9e32baffe65437ded19a0d07543669bbc5 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Feb 2014 18:46:28 -0500 Subject: [PATCH 22/48] use key of remote router as ident key for SessionCreated --- SSU.cpp | 30 +++++++++++++++++++++--------- SSU.h | 2 +- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 1c7d0155..94dbcfb7 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -59,7 +59,9 @@ namespace ssu void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { LogPrint ("Process session request"); - if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, buf, len)) + // use our intro key + if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, + i2p::context.GetRouterInfo (), buf, len)) { m_State = eSessionStateRequestReceived; LogPrint ("Session request received"); @@ -71,11 +73,20 @@ namespace ssu void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len) { 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; - LogPrint ("Session request received"); - // TODO: + LogPrint ("Session created received"); + boost::asio::ip::address_v4 ourAddress (be32toh (*(uint32_t* )(buf + sizeof (SSUHeader) + 257))); + uint16_t ourPort = be16toh (*(uint16_t *)(buf + sizeof (SSUHeader) + 261)); + LogPrint ("Our external address is ", ourAddress.to_string (), ":", ourPort); } } @@ -92,7 +103,7 @@ namespace ssu uint8_t * payload = buf + sizeof (SSUHeader); memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256); payload[256] = 4; // we assume ipv4 - *(uint32_t *)(payload + 257) = address->host.to_v4 ().to_ulong (); // network bytes order already + *(uint32_t *)(payload + 257) = htobe32 (address->host.to_v4 ().to_ulong ()); uint8_t iv[16]; CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); @@ -121,7 +132,7 @@ namespace ssu payload += 256; *payload = 4; // we assume ipv4 payload++; - *(uint32_t *)(payload) = m_RemoteEndpoint.address ().to_v4 ().to_ulong (); // network bytes order already + *(uint32_t *)(payload) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); payload += 4; *(uint16_t *)(payload) = htobe16 (m_RemoteEndpoint.port ()); payload += 2; @@ -149,9 +160,9 @@ namespace ssu m_Server->Send (buf, 368, 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) { // use intro key for verification and decryption @@ -171,7 +182,7 @@ namespace ssu LogPrint ("MAC verifcation failed"); } else - LogPrint ("SSU is not supported"); + LogPrint ("SSU is not supported by ", r.GetIdentHashAbbreviation ()); return false; } @@ -207,6 +218,7 @@ namespace ssu uint8_t * encrypted = &header->flag; uint16_t encryptedLen = len - (encrypted - buf); m_Decryption.SetKeyWithIV (aesKey, 32, header->iv); + encryptedLen = (encryptedLen/16)*16; // make sure 16 bytes boundary m_Decryption.ProcessData (encrypted, encrypted, encryptedLen); } diff --git a/SSU.h b/SSU.h index 6b2d108a..1dcf536e 100644 --- a/SSU.h +++ b/SSU.h @@ -70,7 +70,7 @@ namespace ssu void ProcessSessionCreated (uint8_t * buf, size_t len); void SendSessionCreated (const uint8_t * x); - bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len); + 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 Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey); bool Validate (uint8_t * buf, size_t len, uint8_t * macKey); From 04cf2031ef0d0b659773812475510db494e43215 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Feb 2014 22:20:41 -0500 Subject: [PATCH 23/48] handle received packets in right order --- Streaming.cpp | 90 ++++++++++++++++++++++++++------------------------- Streaming.h | 1 + 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/Streaming.cpp b/Streaming.cpp index 86f2a55c..f73c5125 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -34,55 +34,22 @@ namespace stream if (!m_SendStreamID) 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 (); - LogPrint ("seqn=", receivedSeqn, ", flags=", flags); + LogPrint ("Received seqn=", receivedSeqn); if (!receivedSeqn || receivedSeqn == m_LastReceivedSequenceNumber + 1) { - // we have received next message - packet->offset = packet->GetPayload () - packet->buf; - if (packet->GetLength () > 0) - m_ReceiveQueue.Put (packet); - else - delete packet; - - m_LastReceivedSequenceNumber = receivedSeqn; - SendQuickAck (); + // we have received next in sequence message + ProcessPacket (packet); // we should also try stored messages if any for (auto it = m_SavedPackets.begin (); it != m_SavedPackets.end ();) { if ((*it)->GetSeqn () == m_LastReceivedSequenceNumber + 1) { - Packet * packet = *it; + Packet * savedPacket = *it; m_SavedPackets.erase (it++); - LogPrint ("Process saved packet seqn=", packet->GetSeqn ()); - if (packet->GetLength () > 0) - m_ReceiveQueue.Put (packet); - else - delete packet; - m_LastReceivedSequenceNumber++; - SendQuickAck (); + ProcessPacket (savedPacket); } else break; @@ -106,7 +73,47 @@ namespace stream 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) { LogPrint ("Closed"); @@ -114,11 +121,6 @@ namespace stream m_ReceiveQueue.WakeUp (); } } - - void Stream::SavePacket (Packet * packet) - { - m_SavedPackets.insert (packet); - } size_t Stream::Send (uint8_t * buf, size_t len, int timeout) { diff --git a/Streaming.h b/Streaming.h index 5939d058..18d09b5d 100644 --- a/Streaming.h +++ b/Streaming.h @@ -84,6 +84,7 @@ namespace stream void SendQuickAck (); void SavePacket (Packet * packet); + void ProcessPacket (Packet * packet); private: From 11e11df5ca1453fd819edc6fb811727f13991436 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sun, 2 Feb 2014 20:37:43 +0100 Subject: [PATCH 24/48] Fixing reseed --- Reseed.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Reseed.cpp b/Reseed.cpp index 540caa15..e60ffa44 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "Reseed.h" #include "Log.h" #include "util.h" @@ -56,6 +57,7 @@ namespace data std::string tmpUrl; std::string filename; std::string ignoreFileSuffix = ".zip"; + boost::filesystem::path root = i2p::util::filesystem::GetDataDir(); while (i != j) { name = *i++; @@ -65,9 +67,20 @@ namespace data tmpUrl = reseedHost; tmpUrl.append(name); routerInfo = i2p::util::http::httpRequest(tmpUrl); - filename = "netDb/r"; + 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; From a46f311762825197cfa2f1764e58de0e0e7188e5 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sun, 2 Feb 2014 23:22:00 +0100 Subject: [PATCH 25/48] RouterInfo file size fix --- RouterInfo.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 44bd90e4..1d6eb6d5 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -46,7 +46,11 @@ namespace data if (s.is_open ()) { s.seekg (0,std::ios::end); - m_BufferLen = s.tellg (); + m_BufferLen = s.tellg (); + if (m_BufferLen < 40) + { + LogPrint("File", filename, " is malformed"); + } s.seekg(0, std::ios::beg); s.read(m_Buffer,m_BufferLen); ReadFromBuffer (); From 1efe9cc41ecfa5d3075091c283bf9b1c58e706b2 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sun, 2 Feb 2014 23:23:15 +0100 Subject: [PATCH 26/48] return --- RouterInfo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 1d6eb6d5..3b0054a0 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -50,6 +50,7 @@ namespace data if (m_BufferLen < 40) { LogPrint("File", filename, " is malformed"); + return; } s.seekg(0, std::ios::beg); s.read(m_Buffer,m_BufferLen); From dbd9c5c1051f05ebc9f05bd1375b9173476b5117 Mon Sep 17 00:00:00 2001 From: chertov Date: Mon, 3 Feb 2014 14:13:40 +0400 Subject: [PATCH 27/48] fix windows build, add windows GetDefaultDataDir, add files to project --- Streaming.cpp | 1 + Win32/i2pd.vcxproj | 4 ++++ Win32/i2pd.vcxproj.filters | 12 ++++++++++++ util.cpp | 10 +++++++++- 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Streaming.cpp b/Streaming.cpp index f73c5125..5d59b6f0 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -2,6 +2,7 @@ #include #include #include "Log.h" +#include "I2PEndian.h" #include "RouterInfo.h" #include "RouterContext.h" #include "Tunnel.h" diff --git a/Win32/i2pd.vcxproj b/Win32/i2pd.vcxproj index 353e8afa..c6f95ed7 100644 --- a/Win32/i2pd.vcxproj +++ b/Win32/i2pd.vcxproj @@ -22,6 +22,7 @@ + @@ -31,6 +32,7 @@ + @@ -47,6 +49,7 @@ + @@ -59,6 +62,7 @@ + {930568EC-31C9-406A-AD1C-9636DF5D8FAA} diff --git a/Win32/i2pd.vcxproj.filters b/Win32/i2pd.vcxproj.filters index 152edb53..0eb7dc3d 100644 --- a/Win32/i2pd.vcxproj.filters +++ b/Win32/i2pd.vcxproj.filters @@ -75,6 +75,12 @@ Source Files + + Source Files + + + Source Files + @@ -155,5 +161,11 @@ Header Files + + Header Files + + + Header Files + \ No newline at end of file diff --git a/util.cpp b/util.cpp index 88a1f7c8..1917a984 100644 --- a/util.cpp +++ b/util.cpp @@ -10,9 +10,15 @@ #include #include #include +#include #include "util.h" #include "Log.h" +#ifdef WIN32 +#include +#include +#endif + namespace i2p { namespace util @@ -152,7 +158,9 @@ namespace filesystem // Unix: ~/.i2pd #ifdef WIN32 // Windows - return GetSpecialFolderPath(CSIDL_APPDATA) / "i2pd"; + 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"); From 0171d3040a86e7eb87e2b4abcd89cfd2ca4db396 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 3 Feb 2014 10:51:01 -0500 Subject: [PATCH 28/48] fixed crash --- NTCPSession.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 3e3d551d..e2686248 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -474,7 +474,9 @@ namespace ntcp if (ecode) { 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 { From 6f08edb32feb17545c005a8701ecd4f86b9ee713 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 3 Feb 2014 14:40:38 -0500 Subject: [PATCH 29/48] create MAC key --- SSU.cpp | 10 +++++++--- SSU.h | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 94dbcfb7..5509b96e 100644 --- a/SSU.cpp +++ b/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::SecByteBlock secretKey(dh.AgreedValueLength()); @@ -34,9 +34,13 @@ namespace ssu { aesKey[0] = 0; memcpy (aesKey + 1, secretKey, 31); + memcpy (macKey, secretKey + 31, 32); } - else + else + { 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) @@ -172,7 +176,7 @@ namespace ssu SSUHeader * header = (SSUHeader *)buf; if ((header->flag >> 4) == expectedPayloadType) { - CreateAESKey (buf + sizeof (SSUHeader), m_SessionKey); + CreateAESandMacKey (buf + sizeof (SSUHeader), m_SessionKey, m_MacKey); return true; } else diff --git a/SSU.h b/SSU.h index 1dcf536e..2c797804 100644 --- a/SSU.h +++ b/SSU.h @@ -63,7 +63,7 @@ namespace ssu 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 ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void SendSessionRequest (); @@ -83,7 +83,7 @@ namespace ssu SessionState m_State; CryptoPP::CBC_Mode::Encryption m_Encryption; CryptoPP::CBC_Mode::Decryption m_Decryption; - uint8_t m_SessionKey[32]; + uint8_t m_SessionKey[32], m_MacKey[32]; }; class SSUServer From e24795dd41ca04f71df6e99ba075d964e5807b37 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 3 Feb 2014 21:57:53 -0500 Subject: [PATCH 30/48] pick most recent tunnel from LeaseSet --- LeaseSet.cpp | 6 +++--- LeaseSet.h | 11 ++++++++++- Streaming.cpp | 14 ++++++++------ 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/LeaseSet.cpp b/LeaseSet.cpp index 2b75b463..b62a4598 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -57,13 +57,13 @@ namespace data LogPrint ("LeaseSet verification failed"); } - std::vector LeaseSet::GetNonExpiredLeases () const + std::set LeaseSet::GetNonExpiredLeases () const { auto ts = i2p::util::GetMillisecondsSinceEpoch (); - std::vector leases; + std::set leases; for (auto& it: m_Leases) if (ts < it.endDate) - leases.push_back (it); + leases.insert (it); return leases; } diff --git a/LeaseSet.h b/LeaseSet.h index 294e32d0..6bcc8122 100644 --- a/LeaseSet.h +++ b/LeaseSet.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "Identity.h" namespace i2p @@ -18,6 +19,14 @@ namespace data uint8_t tunnelGateway[32]; uint32_t tunnelID; uint64_t endDate; + + bool operator< (const Lease& other) const + { + if (endDate != other.endDate) + return endDate > other.endDate; + else + return tunnelID < other.tunnelID; + } }; #pragma pack() @@ -34,7 +43,7 @@ namespace data const Identity& GetIdentity () const { return m_Identity; }; const IdentHash& GetIdentHash () const { return m_IdentHash; }; const std::vector& GetLeases () const { return m_Leases; }; - std::vector GetNonExpiredLeases () const; + std::set GetNonExpiredLeases () const; bool HasExpiredLeases () const; bool HasNonExpiredLeases () const; const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; }; diff --git a/Streaming.cpp b/Streaming.cpp index 5d59b6f0..c7cd9ad3 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -173,9 +173,10 @@ namespace stream if (!m_OutboundTunnel) 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); } else @@ -209,7 +210,7 @@ namespace stream auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); if (!leases.empty ()) { - auto& lease = leases[0]; // TODO: + auto& lease = *leases.begin (); // TODO: m_OutboundTunnel->SendTunnelDataMsg (lease.tunnelGateway, lease.tunnelID, msg); LogPrint ("Quick Ack sent"); } @@ -252,11 +253,12 @@ namespace stream I2NPMessage * msg = i2p::garlic::routing.WrapSingleMessage (m_RemoteLeaseSet, 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); - LogPrint ("FIN sent"); + LogPrint ("FIN sent"); } else DeleteI2NPMessage (msg); From 670508016b5472d89e8115f00820d6843733691c Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 4 Feb 2014 14:20:58 -0500 Subject: [PATCH 31/48] SessionConfirmed message --- SSU.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- SSU.h | 4 ++- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 5509b96e..12b9e49b 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -55,6 +55,10 @@ namespace ssu // session created ProcessSessionCreated (buf, len); break; + case eSessionStateCreatedSent: + // session confirmed + ProcessSessionConfirmed (buf, len); + break; default: LogPrint ("SSU state not implemented yet"); } @@ -88,12 +92,35 @@ namespace ssu { m_State = eSessionStateCreatedReceived; LogPrint ("Session created received"); - boost::asio::ip::address_v4 ourAddress (be32toh (*(uint32_t* )(buf + sizeof (SSUHeader) + 257))); - uint16_t ourPort = be16toh (*(uint16_t *)(buf + sizeof (SSUHeader) + 261)); - LogPrint ("Our external address is ", ourAddress.to_string (), ":", ourPort); + 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); + uint32_t relayTag = be32toh (*(uint32_t *)(buf + sizeof (SSUHeader) + 263)); + SendSessionConfirmed (buf + sizeof (SSUHeader), ourAddress, relayTag); } } + 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: + } + else + LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); + } + else + LogPrint ("MAC verifcation failed"); + } + void SSUSession::SendSessionRequest () { auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr; @@ -141,7 +168,7 @@ namespace ssu *(uint16_t *)(payload) = htobe16 (m_RemoteEndpoint.port ()); payload += 2; memcpy (signedData + 512, payload - 6, 6); // remote endpoint IP and port - *(uint32_t *)(signedData + 518) = m_Server->GetEndpoint ().address ().to_v4 ().to_ulong (); // our IP + *(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; @@ -164,6 +191,52 @@ namespace ssu 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; + if (!address) + { + LogPrint ("Missing remote SSU address"); + return; + } + + uint8_t buf[480 + 18]; + uint8_t * payload = buf + sizeof (SSUHeader); + *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 + + // signature + 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, i2p::data::RouterInfo& r, uint8_t * buf, size_t len) { auto address = r.GetSSUAddress (); diff --git a/SSU.h b/SSU.h index 2c797804..c33b3f83 100644 --- a/SSU.h +++ b/SSU.h @@ -30,12 +30,12 @@ namespace ssu const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0; const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1; const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2; - const uint8_t PAYLOAD_TYPE_SESSION_DESTROY = 8; const uint8_t PAYLOAD_TYPE_RELAY_REQUEST = 3; const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4; const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5; const uint8_t PAYLOAD_TYPE_DATA = 6; const uint8_t PAYLOAD_TYPE_TEST = 7; + const uint8_t PAYLOAD_TYPE_SESSION_DESTROY = 8; enum SessionState { @@ -69,6 +69,8 @@ namespace ssu void SendSessionRequest (); void ProcessSessionCreated (uint8_t * buf, size_t len); void SendSessionCreated (const uint8_t * x); + void ProcessSessionConfirmed (uint8_t * buf, size_t len); + void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag); 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); From 82bd8cc69fb593522c23c5b8721049408af4f2aa Mon Sep 17 00:00:00 2001 From: Meeh Date: Wed, 5 Feb 2014 00:15:42 +0100 Subject: [PATCH 32/48] Should fix the segfault at exit --- Queue.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Queue.h b/Queue.h index ae60f099..449ff806 100644 --- a/Queue.h +++ b/Queue.h @@ -99,6 +99,10 @@ namespace util public: MsgQueue (): m_Thread (std::bind (&MsgQueue::Run, this)) {}; + void Stop() + { + m_Thread.detach(); + } private: void Run () From 8f1e300b13b447fa4df974d2d12d1d8f4118fe40 Mon Sep 17 00:00:00 2001 From: Meeh Date: Wed, 5 Feb 2014 00:43:50 +0100 Subject: [PATCH 33/48] Log to file, reload config and daemon mode --- README.md | 17 +++++++++---- i2p.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index dc4e0a8c..20d84e5b 100644 --- a/README.md +++ b/README.md @@ -26,14 +26,21 @@ $ ./i2p --host=YOUR_PUBLIC_IP The client should now reseed by itself. -Other options: -* --port= - The port to listen on -* --httpport= - The http port to listen on - - 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. + + + diff --git a/i2p.cpp b/i2p.cpp index aed38cd0..991c8b8b 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include #include "Log.h" #include "base64.h" #include "Transports.h" @@ -13,6 +16,21 @@ #include "HTTPServer.h" #include "util.h" +void handle_sighup(int n) +{ + 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); +} + int main( int argc, char* argv[] ) { i2p::util::config::OptionParser(argc,argv); @@ -23,10 +41,51 @@ int main( int argc, char* argv[] ) setlocale(LC_ALL, "Russian"); #endif + 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); + struct sigaction sa; + sa.sa_handler = handle_sighup; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if (sigaction(SIGHUP,&sa,0) == -1) + { + LogPrint("Failed to install SIGHUP handler."); + } + + if (i2p::util::config::GetArg("-daemon", 0) == 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; + } + } + + if (i2p::util::config::GetArg("-log", 0) == 1) + { + std::string logfile = i2p::util::filesystem::GetDataDir().string(); + logfile.append("/debug.log"); + LogPrint("Logging to file enabled."); + freopen(logfile.c_str(),"a",stdout); + } + //TODO: This is an ugly workaround. fix it. //TODO: Autodetect public IP. i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), @@ -38,12 +97,21 @@ int main( int argc, char* argv[] ) httpServer.Start (); i2p::data::netdb.Start (); i2p::transports.Start (); - i2p::tunnel::tunnels.Start (); - - std::this_thread::sleep_for (std::chrono::seconds(10000)); + i2p::tunnel::tunnels.Start (); + + int running = 1; + while (running) + { + std::this_thread::sleep_for (std::chrono::seconds(1000)); + } + i2p::tunnel::tunnels.Stop (); i2p::transports.Stop (); i2p::data::netdb.Stop (); - httpServer.Stop (); + httpServer.Stop (); + if (i2p::util::config::GetArg("-log", 0) == 1) + { + fclose (stdout); + } return 0; } From bcf10eb979594b823878847c592b70ab6af1928e Mon Sep 17 00:00:00 2001 From: Meeh Date: Wed, 5 Feb 2014 00:50:13 +0100 Subject: [PATCH 34/48] Try not to break windows builds. --- i2p.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/i2p.cpp b/i2p.cpp index 991c8b8b..468adeeb 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -2,9 +2,13 @@ #include #include #include + +#ifndef _WIN32 #include #include #include +#endif + #include "Log.h" #include "base64.h" #include "Transports.h" @@ -16,6 +20,7 @@ #include "HTTPServer.h" #include "util.h" +#ifndef _WIN32 void handle_sighup(int n) { if (i2p::util::config::GetArg("daemon", 0) == 1) @@ -30,6 +35,7 @@ void handle_sighup(int n) LogPrint("Reloading config."); i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); } +#endif int main( int argc, char* argv[] ) { @@ -46,6 +52,7 @@ int main( int argc, char* argv[] ) LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string()); i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); +#ifndef _WIN32 struct sigaction sa; sa.sa_handler = handle_sighup; sigemptyset(&sa.sa_mask); @@ -77,11 +84,16 @@ int main( int argc, char* argv[] ) return -1; } } +#endif if (i2p::util::config::GetArg("-log", 0) == 1) { std::string logfile = i2p::util::filesystem::GetDataDir().string(); +#ifndef _WIN32 logfile.append("/debug.log"); +#else + logfile.append("\\debug.log"); +#endif LogPrint("Logging to file enabled."); freopen(logfile.c_str(),"a",stdout); } @@ -102,6 +114,7 @@ int main( int argc, char* argv[] ) int running = 1; while (running) { + //TODO Meeh: Find something better to do here. std::this_thread::sleep_for (std::chrono::seconds(1000)); } @@ -109,6 +122,7 @@ int main( int argc, char* argv[] ) i2p::transports.Stop (); i2p::data::netdb.Stop (); httpServer.Stop (); + if (i2p::util::config::GetArg("-log", 0) == 1) { fclose (stdout); From 0dbb2ac55748ab5b28dd3048b599e329060e233d Mon Sep 17 00:00:00 2001 From: Meeh Date: Wed, 5 Feb 2014 01:28:18 +0100 Subject: [PATCH 35/48] Handle shutdown signals --- i2p.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/i2p.cpp b/i2p.cpp index 468adeeb..6636c2b6 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -20,6 +20,10 @@ #include "HTTPServer.h" #include "util.h" + +// Global +int running = 1; + #ifndef _WIN32 void handle_sighup(int n) { @@ -35,8 +39,13 @@ void handle_sighup(int n) LogPrint("Reloading config."); i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); } +void handle_shutdown(int sig) +{ + running = 0; // Exit loop +} #endif + int main( int argc, char* argv[] ) { i2p::util::config::OptionParser(argc,argv); @@ -84,6 +93,11 @@ int main( int argc, char* argv[] ) return -1; } } + + // Handle shutdown + signal(SIGABRT, &handle_shutdown); + signal(SIGTERM, &handle_shutdown); + signal(SIGINT, &handle_shutdown); #endif if (i2p::util::config::GetArg("-log", 0) == 1) @@ -102,21 +116,20 @@ int main( int argc, char* argv[] ) //TODO: Autodetect public IP. i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), i2p::util::config::GetArg("-port", 17070)); - int httpport = i2p::util::config::GetArg("-httpport", 7070); - i2p::util::HTTPServer httpServer (httpport); + i2p::util::HTTPServer httpServer (i2p::util::config::GetArg("-httpport", 7070)); httpServer.Start (); i2p::data::netdb.Start (); i2p::transports.Start (); i2p::tunnel::tunnels.Start (); - int running = 1; while (running) { //TODO Meeh: Find something better to do here. - std::this_thread::sleep_for (std::chrono::seconds(1000)); + std::this_thread::sleep_for (std::chrono::seconds(1)); } + LogPrint("Shutdown started."); i2p::tunnel::tunnels.Stop (); i2p::transports.Stop (); From 135b3f1477ecb252c120570894338b17199beac2 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 4 Feb 2014 22:51:46 -0500 Subject: [PATCH 36/48] take UDP address from actual endpoint --- SSU.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SSU.cpp b/SSU.cpp index 12b9e49b..4a9892ab 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -134,7 +134,7 @@ namespace ssu uint8_t * payload = buf + sizeof (SSUHeader); memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256); payload[256] = 4; // we assume ipv4 - *(uint32_t *)(payload + 257) = htobe32 (address->host.to_v4 ().to_ulong ()); + *(uint32_t *)(payload + 257) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); uint8_t iv[16]; CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); From 728c1a9226109c1449297d6f2f293040d1889ad2 Mon Sep 17 00:00:00 2001 From: chertov Date: Wed, 5 Feb 2014 09:14:07 +0400 Subject: [PATCH 37/48] fix LittleEndian, change endian.h version --- I2PEndian.cpp | 162 +++++++++++++++++++++++----------------------- I2PEndian.h | 16 ++--- LittleBigEndian.h | 12 ++-- Streaming.cpp | 1 - i2p.cpp | 4 ++ portable_endian.h | 115 -------------------------------- 6 files changed, 98 insertions(+), 212 deletions(-) delete mode 100644 portable_endian.h diff --git a/I2PEndian.cpp b/I2PEndian.cpp index fa4e08cb..1fccf47f 100644 --- a/I2PEndian.cpp +++ b/I2PEndian.cpp @@ -1,81 +1,81 @@ -//#include "I2PEndian.h" -// -//// http://habrahabr.ru/post/121811/ -//// http://codepad.org/2ycmkz2y -// -//#include "LittleBigEndian.h" -// -//uint16_t htobe16(uint16_t int16) -//{ -// BigEndian u16(int16); -// return u16.raw_value; -//} -// -//uint32_t htobe32(uint32_t int32) -//{ -// BigEndian u32(int32); -// return u32.raw_value; -//} -// -//uint64_t htobe64(uint64_t int64) -//{ -// BigEndian u64(int64); -// return u64.raw_value; -//} -// -//uint16_t be16toh(uint16_t big16) -//{ -// LittleEndian u16(big16); -// return u16.raw_value; -//} -// -//uint32_t be32toh(uint32_t big32) -//{ -// LittleEndian u32(big32); -// return u32.raw_value; -//} -// -//uint64_t be64toh(uint64_t big64) -//{ -// LittleEndian u64(big64); -// return u64.raw_value; -//} -// -///* it can be used in Windows 8 -//#include -// -//uint16_t htobe16(uint16_t int16) -//{ -// return htons(int16); -//} -// -//uint32_t htobe32(uint32_t int32) -//{ -// return htonl(int32); -//} -// -//uint64_t htobe64(uint64_t int64) -//{ -// // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx -// //return htonll(int64); -// return 0; -//} -// -// -//uint16_t be16toh(uint16_t big16) -//{ -// return ntohs(big16); -//} -// -//uint32_t be32toh(uint32_t big32) -//{ -// return ntohl(big32); -//} -// -//uint64_t be64toh(uint64_t big64) -//{ -// // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx -// //return ntohll(big64); -// return 0; -//} -//*/ \ No newline at end of file +#include "I2PEndian.h" + +// http://habrahabr.ru/post/121811/ +// http://codepad.org/2ycmkz2y + +#include "LittleBigEndian.h" + +uint16_t htobe16(uint16_t int16) +{ + BigEndian u16(int16); + return u16.raw_value; +} + +uint32_t htobe32(uint32_t int32) +{ + BigEndian u32(int32); + return u32.raw_value; +} + +uint64_t htobe64(uint64_t int64) +{ + BigEndian u64(int64); + return u64.raw_value; +} + +uint16_t be16toh(uint16_t big16) +{ + LittleEndian u16(big16); + return u16.raw_value; +} + +uint32_t be32toh(uint32_t big32) +{ + LittleEndian u32(big32); + return u32.raw_value; +} + +uint64_t be64toh(uint64_t big64) +{ + LittleEndian u64(big64); + return u64.raw_value; +} + +/* it can be used in Windows 8 +#include + +uint16_t htobe16(uint16_t int16) +{ + return htons(int16); +} + +uint32_t htobe32(uint32_t int32) +{ + return htonl(int32); +} + +uint64_t htobe64(uint64_t int64) +{ + // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx + //return htonll(int64); + return 0; +} + + +uint16_t be16toh(uint16_t big16) +{ + return ntohs(big16); +} + +uint32_t be32toh(uint32_t big32) +{ + return ntohl(big32); +} + +uint64_t be64toh(uint64_t big64) +{ + // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx + //return ntohll(big64); + return 0; +} +*/ \ No newline at end of file diff --git a/I2PEndian.h b/I2PEndian.h index 3014f564..01ba73e8 100644 --- a/I2PEndian.h +++ b/I2PEndian.h @@ -5,16 +5,14 @@ #include #else #include -// -//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 diff --git a/LittleBigEndian.h b/LittleBigEndian.h index ea879729..69f10ee9 100644 --- a/LittleBigEndian.h +++ b/LittleBigEndian.h @@ -59,12 +59,12 @@ struct LittleEndian return t; } - const T operator = (const T t) - { - for (unsigned i = 0; i < sizeof(T); i++) - bytes[i] = t >> (i << 3); - return t; - } + const T operator = (const T t) + { + for (unsigned i = 0; i < sizeof(T); i++) + bytes[sizeof(T)-1 - i] = static_cast(t >> (i << 3)); + return t; + } // operators diff --git a/Streaming.cpp b/Streaming.cpp index c7cd9ad3..05f838fa 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -2,7 +2,6 @@ #include #include #include "Log.h" -#include "I2PEndian.h" #include "RouterInfo.h" #include "RouterContext.h" #include "Tunnel.h" diff --git a/i2p.cpp b/i2p.cpp index 6636c2b6..24341fe7 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -1,3 +1,7 @@ +#ifdef _WIN32 +#define _CRT_SECURE_NO_WARNINGS // to use freopen +#endif + #include #include #include diff --git a/portable_endian.h b/portable_endian.h deleted file mode 100644 index 3355d2b9..00000000 --- a/portable_endian.h +++ /dev/null @@ -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 - -#elif defined(__APPLE__) - -# include - -# 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 - -#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) - -# include - -# 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 -#undef NOMINMAX -//# include - -# 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 \ No newline at end of file From 6afc32510bc48fc18f1f04dcbb12dc24ecf0ecb7 Mon Sep 17 00:00:00 2001 From: Meeh Date: Wed, 5 Feb 2014 09:45:57 +0100 Subject: [PATCH 38/48] Rewriting signal handler, adding pid file support. --- i2p.cpp | 89 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/i2p.cpp b/i2p.cpp index 6636c2b6..00f1abb7 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -25,23 +25,29 @@ int running = 1; #ifndef _WIN32 -void handle_sighup(int n) +void handle_signal(int sig) { - if (i2p::util::config::GetArg("daemon", 0) == 1) + switch (sig) { - static bool first=true; - if (first) - { - first=false; - return; - } + 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; } - LogPrint("Reloading config."); - i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); -} -void handle_shutdown(int sig) -{ - running = 0; // Exit loop } #endif @@ -62,15 +68,6 @@ int main( int argc, char* argv[] ) i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); #ifndef _WIN32 - struct sigaction sa; - sa.sa_handler = handle_sighup; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - if (sigaction(SIGHUP,&sa,0) == -1) - { - LogPrint("Failed to install SIGHUP handler."); - } - if (i2p::util::config::GetArg("-daemon", 0) == 1) { pid_t pid; @@ -92,12 +89,36 @@ int main( int argc, char* argv[] ) LogPrint("Error, could not create process group."); return -1; } + chdir(i2p::util::filesystem::GetDataDir().string().c_str()); } - // Handle shutdown - signal(SIGABRT, &handle_shutdown); - signal(SIGTERM, &handle_shutdown); - signal(SIGINT, &handle_shutdown); + // 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 create 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 if (i2p::util::config::GetArg("-log", 0) == 1) @@ -119,9 +140,9 @@ int main( int argc, char* argv[] ) i2p::util::HTTPServer httpServer (i2p::util::config::GetArg("-httpport", 7070)); - httpServer.Start (); + httpServer.Start (); i2p::data::netdb.Start (); - i2p::transports.Start (); + i2p::transports.Start (); i2p::tunnel::tunnels.Start (); while (running) @@ -131,14 +152,18 @@ int main( int argc, char* argv[] ) } LogPrint("Shutdown started."); - i2p::tunnel::tunnels.Stop (); - i2p::transports.Stop (); - i2p::data::netdb.Stop (); + i2p::tunnel::tunnels.Stop (); + i2p::transports.Stop (); + i2p::data::netdb.Stop (); httpServer.Stop (); if (i2p::util::config::GetArg("-log", 0) == 1) { fclose (stdout); } +#ifndef _WIN32 + close(pidFilehandle); + unlink(pidfile.c_str()); +#endif return 0; } From b14d3b7c0166025848460cd095f1282feb40893f Mon Sep 17 00:00:00 2001 From: Meeh Date: Wed, 5 Feb 2014 13:47:00 +0100 Subject: [PATCH 39/48] Changed error text --- i2p.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i2p.cpp b/i2p.cpp index 00f1abb7..b4c47e10 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -103,7 +103,7 @@ int main( int argc, char* argv[] ) } if (lockf(pidFilehandle,F_TLOCK,0) == -1) { - LogPrint("Error, could not create pid file (", pidfile, ")\nIs an instance already running?"); + LogPrint("Error, could not lock pid file (", pidfile, ")\nIs an instance already running?"); return -1; } char pid[10]; From 53cd9c24182921e12906229488034d815fc85767 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 5 Feb 2014 15:07:47 -0500 Subject: [PATCH 40/48] parse data message --- SSU.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SSU.h | 2 ++ 2 files changed, 63 insertions(+) diff --git a/SSU.cpp b/SSU.cpp index 4a9892ab..521117ba 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -47,6 +47,11 @@ namespace ssu { switch (m_State) { + case eSessionStateEstablised: + // most common case + ProcessMessage (buf, len); + break; + // establishing case eSessionStateUnknown: // session request ProcessSessionRequest (buf, len, senderEndpoint); @@ -64,6 +69,34 @@ namespace ssu } } + 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_DESTROY: + 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) { LogPrint ("Process session request"); @@ -98,6 +131,7 @@ namespace ssu LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort); uint32_t relayTag = be32toh (*(uint32_t *)(buf + sizeof (SSUHeader) + 263)); SendSessionConfirmed (buf + sizeof (SSUHeader), ourAddress, relayTag); + m_State = eSessionStateEstablised; } } @@ -113,6 +147,7 @@ namespace ssu m_State = eSessionStateConfirmedReceived; LogPrint ("Session confirmed received"); // TODO: + m_State = eSessionStateEstablised; } else LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); @@ -327,6 +362,32 @@ namespace ssu // TODO: } + void SSUSession::ProcessData (uint8_t * buf, size_t len) + { + //uint8_t * start = buf; + uint8_t flag = *buf; + buf++; + LogPrint ("Process SSU data flags=", (int)flag); + if (flag) + { + //TODO: process options + return; + } + uint8_t numFragments = *buf; // number of fragments + buf++; + 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 = be16toh (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 ", (int)numFragments, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last"); + } + SSUServer::SSUServer (boost::asio::io_service& service, int port): m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint) { diff --git a/SSU.h b/SSU.h index c33b3f83..aee160ae 100644 --- a/SSU.h +++ b/SSU.h @@ -65,12 +65,14 @@ namespace ssu 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 SendSessionRequest (); void ProcessSessionCreated (uint8_t * buf, size_t len); void SendSessionCreated (const uint8_t * x); void ProcessSessionConfirmed (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); 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); From fd80a13495a01bfa1d51f16f643fc4cb92916a5a Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 5 Feb 2014 19:11:38 -0500 Subject: [PATCH 41/48] handle multiple fragments in one packet --- SSU.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 521117ba..314a62da 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -368,24 +368,23 @@ namespace ssu uint8_t flag = *buf; buf++; LogPrint ("Process SSU data flags=", (int)flag); - if (flag) - { - //TODO: process options - return; - } uint8_t numFragments = *buf; // number of fragments buf++; - 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 = be16toh (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 ", (int)numFragments, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last"); + 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"); + buf += fragmentSize; + } } SSUServer::SSUServer (boost::asio::io_service& service, int port): From d04f9e723c3c2d94b529376a354cbf37fd3867da Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 6 Feb 2014 10:16:50 -0500 Subject: [PATCH 42/48] handle recieved I2NP message --- SSU.cpp | 27 ++++++++++++++++++++++++++- SSU.h | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/SSU.cpp b/SSU.cpp index 314a62da..4fbd2696 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -382,7 +382,32 @@ namespace ssu 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"); + 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; + else + // TODO: + LogPrint ("Unexpected follow-on fragment ", fragmentNum, " of message ", msgID); + } + else // first fragment + msg = NewI2NPMessage (); + if (msg) + { + memcpy (msg->buf + msg->len, buf, fragmentSize); + msg->len += fragmentSize; + if (!fragmentNum && !isLast) + m_IncomleteMessages[msgID] = msg; + if (isLast) + { + if (fragmentNum > 0) + m_IncomleteMessages.erase (msgID); + i2p::HandleI2NPMessage (msg, false); + } + } buf += fragmentSize; } } diff --git a/SSU.h b/SSU.h index aee160ae..a27743a0 100644 --- a/SSU.h +++ b/SSU.h @@ -88,6 +88,7 @@ namespace ssu CryptoPP::CBC_Mode::Encryption m_Encryption; CryptoPP::CBC_Mode::Decryption m_Decryption; uint8_t m_SessionKey[32], m_MacKey[32]; + std::map m_IncomleteMessages; }; class SSUServer From 656392fe1e789910c68f988162dcd53a6f1be9ac Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 7 Feb 2014 11:26:00 -0500 Subject: [PATCH 43/48] handle SSU I2NP header --- I2NPProtocol.h | 20 ++++++++++++++++++++ SSU.cpp | 16 ++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 7f47601e..3905da5b 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -4,6 +4,7 @@ #include #include #include +#include "I2PEndian.h" #include "RouterInfo.h" namespace i2p @@ -19,6 +20,12 @@ namespace i2p uint8_t chks; }; + struct I2NPHeaderShort + { + uint8_t typeID; + uint32_t shortExpiration; + }; + struct I2NPDatabaseStoreMsg { uint8_t key[32]; @@ -101,6 +108,19 @@ namespace i2p len = offset + other.GetLength (); 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 (); void DeleteI2NPMessage (I2NPMessage * msg); diff --git a/SSU.cpp b/SSU.cpp index 4fbd2696..ea7368bc 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -388,23 +388,31 @@ namespace ssu { 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 (); - if (msg) { - memcpy (msg->buf + msg->len, buf, fragmentSize); - msg->len += fragmentSize; + 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); } } From 1c1103dcce1863434673eb8e29ea9b55f3169450 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 7 Feb 2014 15:47:10 -0500 Subject: [PATCH 44/48] send ack --- SSU.cpp | 22 +++++++++++++++++++++- SSU.h | 9 +++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/SSU.cpp b/SSU.cpp index ea7368bc..91ae1bec 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -382,7 +382,7 @@ namespace ssu 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"); + 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 { @@ -414,15 +414,35 @@ namespace ssu 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]; // actual length is 44 = 37 + 7 but pad it to multiple of 16 + uint8_t iv[16]; + *buf = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag + buf[1] = 1; // number of ACKs + *(uint32_t *)(buf + 2) = htobe32 (msgID); // msgID + buf[6] = 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_State = eSessionStateConfirmedSent; + 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 () diff --git a/SSU.h b/SSU.h index a27743a0..0ddaa5c5 100644 --- a/SSU.h +++ b/SSU.h @@ -37,6 +37,14 @@ namespace ssu const uint8_t PAYLOAD_TYPE_TEST = 7; const uint8_t PAYLOAD_TYPE_SESSION_DESTROY = 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 { eSessionStateUnknown, @@ -73,6 +81,7 @@ namespace ssu void ProcessSessionConfirmed (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); 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); From 9897a49e1ad42c7a44205cc0c01813bd91c93f8c Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 8 Feb 2014 03:15:08 +0100 Subject: [PATCH 45/48] Rewrite the thread stop in Queue --- Queue.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Queue.h b/Queue.h index 449ff806..316084a9 100644 --- a/Queue.h +++ b/Queue.h @@ -98,17 +98,18 @@ namespace util { public: - MsgQueue (): m_Thread (std::bind (&MsgQueue::Run, this)) {}; + MsgQueue (): m_Thread (std::bind (&MsgQueue::Run, this)) , running(1) {}; void Stop() { - m_Thread.detach(); + running = 0; + m_Thread.join(); } private: void Run () { Msg * msg = nullptr; - while ((msg = Queue::GetNext ()) != nullptr) + while ((msg = Queue::GetNext ()) != nullptr && running) { msg->Process (); delete msg; @@ -117,6 +118,7 @@ namespace util private: std::thread m_Thread; + int running; }; } } From 9b1e7956cb8b897628960e721571ce7c69bdfe1d Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 8 Feb 2014 03:16:52 +0100 Subject: [PATCH 46/48] defining vars should cost less than function calls --- i2p.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/i2p.cpp b/i2p.cpp index 355c2003..97914b5e 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -27,6 +27,7 @@ // Global int running = 1; +int isDaemon; #ifndef _WIN32 void handle_signal(int sig) @@ -59,6 +60,7 @@ void handle_signal(int sig) int main( int argc, char* argv[] ) { i2p::util::config::OptionParser(argc,argv); + isDaemon = i2p::util::config::GetArg("-daemon", 0); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); @@ -71,8 +73,22 @@ int main( int argc, char* argv[] ) LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string()); i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); + int isLogging = i2p::util::config::GetArg("-log", 0); + if (isLogging == 1) + { + std::string logfile = i2p::util::filesystem::GetDataDir().string(); #ifndef _WIN32 - if (i2p::util::config::GetArg("-daemon", 0) == 1) + 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(); @@ -125,18 +141,6 @@ int main( int argc, char* argv[] ) sigaction(SIGINT,&sa,0); #endif - if (i2p::util::config::GetArg("-log", 0) == 1) - { - std::string logfile = i2p::util::filesystem::GetDataDir().string(); -#ifndef _WIN32 - logfile.append("/debug.log"); -#else - logfile.append("\\debug.log"); -#endif - LogPrint("Logging to file enabled."); - freopen(logfile.c_str(),"a",stdout); - } - //TODO: This is an ugly workaround. fix it. //TODO: Autodetect public IP. i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), @@ -161,7 +165,7 @@ int main( int argc, char* argv[] ) i2p::data::netdb.Stop (); httpServer.Stop (); - if (i2p::util::config::GetArg("-log", 0) == 1) + if (isLogging == 1) { fclose (stdout); } From 202e3eeb2ad7e66a35fa416abe131a6f8e4e85bf Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 7 Feb 2014 21:42:35 -0500 Subject: [PATCH 47/48] process ACKs --- SSU.cpp | 41 +++++++++++++++++++++++++++++++++-------- SSU.h | 2 +- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 91ae1bec..2c85f137 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -47,7 +47,7 @@ namespace ssu { switch (m_State) { - case eSessionStateEstablised: + case eSessionStateEstablished: // most common case ProcessMessage (buf, len); break; @@ -131,7 +131,7 @@ namespace ssu LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort); uint32_t relayTag = be32toh (*(uint32_t *)(buf + sizeof (SSUHeader) + 263)); SendSessionConfirmed (buf + sizeof (SSUHeader), ourAddress, relayTag); - m_State = eSessionStateEstablised; + m_State = eSessionStateEstablished; } } @@ -147,7 +147,7 @@ namespace ssu m_State = eSessionStateConfirmedReceived; LogPrint ("Session confirmed received"); // TODO: - m_State = eSessionStateEstablised; + m_State = eSessionStateEstablished; } else LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); @@ -368,6 +368,28 @@ namespace ssu 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++) @@ -425,16 +447,19 @@ namespace ssu { uint8_t buf[48]; // actual length is 44 = 37 + 7 but pad it to multiple of 16 uint8_t iv[16]; - *buf = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag - buf[1] = 1; // number of ACKs - *(uint32_t *)(buf + 2) = htobe32 (msgID); // msgID - buf[6] = 0; // number of fragments + 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_State = eSessionStateConfirmedSent; m_Server->Send (buf, 48, m_RemoteEndpoint); } diff --git a/SSU.h b/SSU.h index 0ddaa5c5..3a6c029c 100644 --- a/SSU.h +++ b/SSU.h @@ -54,7 +54,7 @@ namespace ssu eSessionStateCreatedReceived, eSessionStateConfirmedSent, eSessionStateConfirmedReceived, - eSessionStateEstablised + eSessionStateEstablished }; class SSUServer; From ec5eafafebef3ddaf6e521a93dcf1ffe6fb28569 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 8 Feb 2014 21:06:40 -0500 Subject: [PATCH 48/48] external IP detection --- RouterContext.cpp | 7 +++++++ RouterContext.h | 1 + RouterInfo.cpp | 8 ++++++++ RouterInfo.h | 3 ++- SSU.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- SSU.h | 11 ++++++++--- Transports.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- Transports.h | 4 ++++ 8 files changed, 106 insertions(+), 9 deletions(-) diff --git a/RouterContext.cpp b/RouterContext.cpp index 68f6508a..768b92a3 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -52,6 +52,13 @@ namespace i2p 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) { diff --git a/RouterContext.h b/RouterContext.h index f43094c1..0cbd0bc7 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -28,6 +28,7 @@ namespace i2p void Sign (uint8_t * buf, int len, uint8_t * signature); void OverrideNTCPAddress (const char * host, int port); // temporary + void UpdateAddress (const char * host); // called from SSU private: diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 3b0054a0..f4668921 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -294,6 +294,14 @@ namespace data else 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) { diff --git a/RouterInfo.h b/RouterInfo.h index d7fc6dd9..3b28fee7 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -53,7 +53,7 @@ namespace data const char * GetIdentHashBase64 () const { return m_IdentHashBase64; }; const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; }; uint64_t GetTimestamp () const { return m_Timestamp; }; - const std::vector
& GetAddresses () const { return m_Addresses; }; + std::vector
& GetAddresses () { return m_Addresses; }; Address * GetNTCPAddress (bool v4only = true); Address * GetSSUAddress (bool v4only = true); const RoutingKey& GetRoutingKey () const { return m_RoutingKey; }; @@ -63,6 +63,7 @@ namespace data const char * GetProperty (const char * key) const; bool IsFloodfill () 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; }; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; diff --git a/SSU.cpp b/SSU.cpp index 2c85f137..57ebdce9 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -85,7 +85,7 @@ namespace ssu case PAYLOAD_TYPE_TEST: LogPrint ("SSU test received"); break; - case PAYLOAD_TYPE_SESSION_DESTROY: + case PAYLOAD_TYPE_SESSION_DESTROYED: LogPrint ("SSU session destroy received"); break; default: @@ -129,6 +129,7 @@ namespace ssu 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; @@ -357,6 +358,11 @@ namespace ssu SendSessionRequest (); } + void SSUSession::Close () + { + SendSesionDestroyed (); + } + void SSUSession::SendI2NPMessage (I2NPMessage * msg) { // TODO: @@ -445,7 +451,7 @@ namespace ssu void SSUSession::SendMsgAck (uint32_t msgID) { - uint8_t buf[48]; // actual length is 44 = 37 + 7 but pad it to multiple of 16 + 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 @@ -463,6 +469,16 @@ namespace ssu 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) { @@ -546,6 +562,26 @@ namespace ssu } 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 (); + } } } diff --git a/SSU.h b/SSU.h index 3a6c029c..15467262 100644 --- a/SSU.h +++ b/SSU.h @@ -35,7 +35,7 @@ namespace ssu const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5; const uint8_t PAYLOAD_TYPE_DATA = 6; const uint8_t PAYLOAD_TYPE_TEST = 7; - const uint8_t PAYLOAD_TYPE_SESSION_DESTROY = 8; + const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8; // data flags const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02; @@ -67,6 +67,8 @@ namespace ssu void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void Connect (); + void Close (); + boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; void SendI2NPMessage (I2NPMessage * msg); private: @@ -82,7 +84,8 @@ namespace ssu 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 Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey); @@ -109,7 +112,9 @@ namespace ssu void Start (); void Stop (); 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); diff --git a/Transports.cpp b/Transports.cpp index c3b96d78..8ea6c05f 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -25,6 +25,7 @@ namespace i2p { m_IsRunning = true; m_Thread = new std::thread (std::bind (&Transports::Run, this)); + m_Timer = new boost::asio::deadline_timer (m_Service); // create acceptors auto addresses = context.GetRouterInfo ().GetAddresses (); for (auto& address : addresses) @@ -38,9 +39,11 @@ namespace i2p auto conn = new i2p::ntcp::NTCPServerConnection (m_Service); m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this, conn, boost::asio::placeholders::error)); - } + // temporary always run SSU server + // TODO: uncomment following lines later + /*} else if (address.transportStyle == RouterInfo::eTransportSSU) - { + {*/ if (!m_SSUServer) { m_SSUServer = new i2p::ssu::SSUServer (m_Service, address.port); @@ -51,6 +54,9 @@ namespace i2p LogPrint ("SSU server already exists"); } } + + // TODO: do it for SSU only + DetectExternalIP (); } void Transports::Stop () @@ -59,7 +65,10 @@ namespace i2p delete session.second; m_NTCPSessions.clear (); delete m_NTCPAcceptor; - + + m_Timer->cancel (); + delete m_Timer; + if (m_SSUServer) { m_SSUServer->Stop (); @@ -173,4 +182,30 @@ namespace i2p else 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(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 (); + } + } + } diff --git a/Transports.h b/Transports.h index 03f6cf35..12bd8f21 100644 --- a/Transports.h +++ b/Transports.h @@ -38,6 +38,9 @@ namespace i2p void Run (); void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error); void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); + + void DetectExternalIP (); + void HandleTimer (const boost::system::error_code& ecode); private: @@ -49,6 +52,7 @@ namespace i2p std::map m_NTCPSessions; i2p::ssu::SSUServer * m_SSUServer; + boost::asio::deadline_timer * m_Timer; public: