diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a00511cd..00000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: cpp -compiler: gcc -cache: apt -branches: - only: - - master -before_install: - - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test # GCC 4.7 - - sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu/ quantal main universe" # Boost 1.50 - - sudo apt-get update -qq - - sudo apt-get install -qq libboost1.50-all-dev libcrypto++9 libcrypto++-dev -script: - - make -notifications: - email: - recipients: - - meeh@sigterm.no - on_success: change - on_failure: always - irc: - channels: - - "irc.freenode.net#i2p-dev" - template: - - "%{repository}/%{branch} (%{commit} - %{author}): %{message}" - on_failure: always - on_success: change - - diff --git a/Daemon.cpp b/Daemon.cpp index f5ee6549..2cc8b9e7 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -15,6 +15,7 @@ #include "Streaming.h" #include "HTTPServer.h" #include "HTTPProxy.h" +#include "SOCKS.h" namespace i2p { @@ -23,14 +24,16 @@ namespace i2p class Daemon_Singleton::Daemon_Singleton_Private { public: - Daemon_Singleton_Private() : httpServer(nullptr), httpProxy(nullptr) { }; + Daemon_Singleton_Private() : httpServer(nullptr), httpProxy(nullptr), socksProxy(nullptr) { }; ~Daemon_Singleton_Private() { delete httpServer; delete httpProxy; + delete socksProxy; }; i2p::util::HTTPServer *httpServer; i2p::proxy::HTTPProxy *httpProxy; + i2p::proxy::SOCKSProxy *socksProxy; }; Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {}; @@ -55,29 +58,35 @@ namespace i2p i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), i2p::util::config::GetArg("-port", 17007)); - if (isLogging == 1) - { - std::string logfile_path = i2p::util::filesystem::GetDataDir().string(); -#ifndef _WIN32 - logfile_path.append("/debug.log"); -#else - logfile_path.append("\\debug.log"); -#endif - g_Log.SetLogFile (logfile_path); + LogPrint("CMD parameters:"); + for (int i = 0; i < argc; ++i) + LogPrint(i, " ", argv[i]); - LogPrint("CMD parameters:"); - for (int i = 0; i < argc; ++i) - LogPrint(i, " ", argv[i]); - - } return true; } bool Daemon_Singleton::start() { + // initialize log + if (isLogging) + { + if (isDaemon) + { + std::string logfile_path = i2p::util::filesystem::GetDataDir().string(); + #ifndef _WIN32 + logfile_path.append("/debug.log"); + #else + logfile_path.append("\\debug.log"); + #endif + StartLog (logfile_path); + } + else + StartLog (""); // write to stdout + } + d.httpServer = new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070)); d.httpServer->Start(); - LogPrint("HTTPServer started"); + LogPrint("HTTP Server started"); i2p::data::netdb.Start(); LogPrint("NetDB started"); @@ -92,8 +101,10 @@ namespace i2p d.httpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyport", 4446)); d.httpProxy->Start(); - LogPrint("Proxy started"); - + LogPrint("HTTP Proxy started"); + d.socksProxy = new i2p::proxy::SOCKSProxy(i2p::util::config::GetArg("-socksproxyport", 4447)); + d.socksProxy->Start(); + LogPrint("SOCKS Proxy Started"); return true; } @@ -102,7 +113,9 @@ namespace i2p LogPrint("Shutdown started."); d.httpProxy->Stop(); - LogPrint("HTTPProxy stoped"); + LogPrint("HTTP Proxy stoped"); + d.socksProxy->Stop(); + LogPrint("SOCKS Proxy stoped"); i2p::stream::StopStreaming(); LogPrint("Streaming stoped"); i2p::garlic::routing.Stop(); @@ -114,16 +127,12 @@ namespace i2p i2p::data::netdb.Stop(); LogPrint("NetDB stoped"); d.httpServer->Stop(); - LogPrint("HTTPServer stoped"); - + LogPrint("HTTP Server stoped"); + StopLog (); + delete d.socksProxy; d.socksProxy = nullptr; delete d.httpProxy; d.httpProxy = nullptr; delete d.httpServer; d.httpServer = nullptr; - if (isLogging == 1) - { - fclose(stdout); - } - return true; } } diff --git a/DaemonLinux.cpp b/DaemonLinux.cpp index 119752ac..530eb077 100644 --- a/DaemonLinux.cpp +++ b/DaemonLinux.cpp @@ -48,24 +48,29 @@ namespace i2p { pid_t pid; pid = fork(); - if (pid > 0) - { - g_Log.Stop(); - return 0; - } - if (pid < 0) - { - return -1; - } + if (pid > 0) // parent + ::exit (EXIT_SUCCESS); + if (pid < 0) // error + return false; + + // child umask(0); int sid = setsid(); if (sid < 0) { LogPrint("Error, could not create process group."); - return -1; + return false; } chdir(i2p::util::filesystem::GetDataDir().string().c_str()); + + // close stdin/stdout/stderr descriptors + ::close (0); + ::open ("/dev/null", O_RDWR); + ::close (1); + ::open ("/dev/null", O_RDWR); + ::close (2); + ::open ("/dev/null", O_RDWR); } // Pidfile @@ -75,12 +80,12 @@ namespace i2p if (pidFilehandle == -1) { LogPrint("Error, could not create pid file (", pidfile, ")\nIs an instance already running?"); - return -1; + return false; } if (lockf(pidFilehandle, F_TLOCK, 0) == -1) { LogPrint("Error, could not lock pid file (", pidfile, ")\nIs an instance already running?"); - return -1; + return false; } char pid[10]; sprintf(pid, "%d\n", getpid()); @@ -101,12 +106,10 @@ namespace i2p bool DaemonLinux::stop() { - Daemon_Singleton::stop(); - close(pidFilehandle); unlink(pidfile.c_str()); - return true; + return Daemon_Singleton::stop(); } } diff --git a/Garlic.cpp b/Garlic.cpp index 85294271..e86374f6 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -14,7 +14,7 @@ namespace i2p { namespace garlic { - GarlicRoutingSession::GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags): + GarlicRoutingSession::GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags): m_Destination (destination), m_FirstMsgID (0), m_IsAcknowledged (false), m_NumTags (numTags), m_NextTag (-1), m_SessionTags (0), m_TagsCreationTime (0) { @@ -23,13 +23,23 @@ namespace garlic m_Encryption.SetKey (m_SessionKey); if (m_NumTags > 0) { - m_SessionTags = new uint8_t[m_NumTags*32]; + m_SessionTags = new SessionTag[m_NumTags]; GenerateSessionTags (); } else m_SessionTags = nullptr; } + GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag): + m_Destination (nullptr), m_FirstMsgID (0), m_IsAcknowledged (true), m_NumTags (1), m_NextTag (0) + { + memcpy (m_SessionKey, sessionKey, 32); + m_Encryption.SetKey (m_SessionKey); + m_SessionTags = new SessionTag[1]; // 1 tag + m_SessionTags[0] = sessionTag; + m_TagsCreationTime = i2p::util::GetSecondsSinceEpoch (); + } + GarlicRoutingSession::~GarlicRoutingSession () { delete[] m_SessionTags; @@ -40,13 +50,13 @@ namespace garlic if (m_SessionTags) { for (int i = 0; i < m_NumTags; i++) - m_Rnd.GenerateBlock (m_SessionTags + i*32, 32); + m_Rnd.GenerateBlock (m_SessionTags[i], 32); m_TagsCreationTime = i2p::util::GetSecondsSinceEpoch (); SetAcknowledged (false); } } - I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg, const I2NPMessage * leaseSet) + I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet) { I2NPMessage * m = NewI2NPMessage (); size_t len = 0; @@ -71,13 +81,18 @@ namespace garlic // create message if (m_NextTag < 0 || !m_NumTags) // new session { + if (!m_Destination) + { + LogPrint ("Can't use ElGamal for unknown destination"); + return nullptr; + } // create ElGamal block ElGamalBlock elGamal; memcpy (elGamal.sessionKey, m_SessionKey, 32); m_Rnd.GenerateBlock (elGamal.preIV, 32); // Pre-IV uint8_t iv[32]; // IV is first 16 bytes CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); - m_Destination.GetElGamalEncryption ()->Encrypt ((uint8_t *)&elGamal, sizeof(elGamal), buf, true); + m_Destination->GetElGamalEncryption ()->Encrypt ((uint8_t *)&elGamal, sizeof(elGamal), buf, true); m_Encryption.SetIV (iv); buf += 514; len += 514; @@ -85,9 +100,9 @@ namespace garlic else // existing session { // session tag - memcpy (buf, m_SessionTags + m_NextTag*32, 32); + memcpy (buf, m_SessionTags[m_NextTag], 32); uint8_t iv[32]; // IV is first 16 bytes - CryptoPP::SHA256().CalculateDigest(iv, m_SessionTags + m_NextTag*32, 32); + CryptoPP::SHA256().CalculateDigest(iv, m_SessionTags[m_NextTag], 32); m_Encryption.SetIV (iv); buf += 32; len += 32; @@ -107,6 +122,8 @@ namespace garlic FillI2NPMessageHeader (m, eI2NPGarlic); if (msg) DeleteI2NPMessage (msg); + if (leaseSet) + DeleteI2NPMessage (leaseSet); return m; } @@ -117,8 +134,11 @@ namespace garlic blockSize += 2; if (m_NextTag < 0) // session tags recreated { - memcpy (buf + blockSize, m_SessionTags, m_NumTags*32); // tags - blockSize += m_NumTags*32; + for (int i = 0; i < m_NumTags; i++) + { + memcpy (buf + blockSize, m_SessionTags[i], 32); // tags + blockSize += 32; + } } uint32_t * payloadSize = (uint32_t *)(buf + blockSize); blockSize += 4; @@ -161,7 +181,7 @@ namespace garlic } if (msg) // clove message ifself if presented { - size += CreateGarlicClove (payload + size, msg, m_Destination.IsDestination ()); + size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false); (*numCloves)++; } @@ -178,11 +198,11 @@ namespace garlic { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec size_t size = 0; - if (isDestination) + if (isDestination && m_Destination) { buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination size++; - memcpy (buf + size, m_Destination.GetIdentHash (), 32); + memcpy (buf + size, m_Destination->GetIdentHash (), 32); size += 32; } else @@ -249,11 +269,18 @@ namespace garlic for (auto it: m_Sessions) delete it.second; m_Sessions.clear (); - for (auto it: m_SessionDecryptions) - delete it; - m_SessionDecryptions.clear (); + // TODO: delete remaining session decryptions + m_SessionTags.clear (); } + void GarlicRouting::AddSessionKey (const uint8_t * key, const uint8_t * tag) + { + SessionDecryption * decryption = new SessionDecryption; + decryption->SetKey (key); + decryption->SetTagCount (1); + m_SessionTags[SessionTag(tag)] = decryption; + } + I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg) { auto it = m_Sessions.find (destination.GetIdentHash ()); @@ -262,14 +289,14 @@ namespace garlic delete it->second; m_Sessions.erase (it); } - GarlicRoutingSession * session = new GarlicRoutingSession (destination, 0); // not follow-on messages expected + GarlicRoutingSession * session = new GarlicRoutingSession (&destination, 0); // not follow-on messages expected m_Sessions[destination.GetIdentHash ()] = session; return session->WrapSingleMessage (msg, nullptr); } I2NPMessage * GarlicRouting::WrapMessage (const i2p::data::RoutingDestination& destination, - I2NPMessage * msg, const I2NPMessage * leaseSet) + I2NPMessage * msg, I2NPMessage * leaseSet) { auto it = m_Sessions.find (destination.GetIdentHash ()); GarlicRoutingSession * session = nullptr; @@ -277,7 +304,7 @@ namespace garlic session = it->second; if (!session) { - session = new GarlicRoutingSession (destination, 32); + session = new GarlicRoutingSession (&destination, 32); m_Sessions[destination.GetIdentHash ()] = session; } @@ -297,8 +324,7 @@ namespace garlic uint8_t * buf = msg->GetPayload (); uint32_t length = be32toh (*(uint32_t *)buf); buf += 4; - std::string sessionTag((const char *)buf, 32); - auto it = m_SessionTags.find (sessionTag); + auto it = m_SessionTags.find (SessionTag(buf)); if (it != m_SessionTags.end ()) { // existing session @@ -306,7 +332,9 @@ namespace garlic CryptoPP::SHA256().CalculateDigest(iv, buf, 32); it->second->SetIV (iv); it->second->Decrypt (buf + 32, length - 32, buf + 32); + it->second->UseTag (); HandleAESBlock (buf + 32, length - 32, it->second); + if (!it->second->GetTagCount ()) delete it->second; // all tags were used m_SessionTags.erase (it); // tag might be used only once } else @@ -320,8 +348,7 @@ namespace garlic pool ? pool->GetEncryptionPrivateKey () : i2p::context.GetPrivateKey (), buf, (uint8_t *)&elGamal, true)) { - i2p::crypto::CBCDecryption * decryption = new i2p::crypto::CBCDecryption; - m_SessionDecryptions.push_back (decryption); + SessionDecryption * decryption = new SessionDecryption; decryption->SetKey (elGamal.sessionKey); uint8_t iv[32]; // IV is first 16 bytes CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); @@ -335,12 +362,16 @@ namespace garlic DeleteI2NPMessage (msg); } - void GarlicRouting::HandleAESBlock (uint8_t * buf, size_t len, i2p::crypto::CBCDecryption * decryption) + void GarlicRouting::HandleAESBlock (uint8_t * buf, size_t len, SessionDecryption * decryption) { uint16_t tagCount = be16toh (*(uint16_t *)buf); - buf += 2; - for (int i = 0; i < tagCount; i++) - m_SessionTags[std::string ((const char *)(buf + i*32), 32)] = decryption; + buf += 2; + if (tagCount > 0) + { + decryption->AddTagCount (tagCount); + for (int i = 0; i < tagCount; i++) + m_SessionTags[SessionTag(buf + i*32)] = decryption; + } buf += tagCount*32; uint32_t payloadSize = be32toh (*(uint32_t *)buf); if (payloadSize > len) @@ -387,7 +418,7 @@ namespace garlic { case eGarlicDeliveryTypeLocal: LogPrint ("Garlic type local"); - i2p::HandleI2NPMessage (buf, len); + i2p::HandleI2NPMessage (CreateI2NPMessage (buf, len)); break; case eGarlicDeliveryTypeDestination: { diff --git a/Garlic.h b/Garlic.h index 7ffb4ce6..0eb58dee 100644 --- a/Garlic.h +++ b/Garlic.h @@ -36,13 +36,16 @@ namespace garlic #pragma pack() const int TAGS_EXPIRATION_TIMEOUT = 900; // 15 minutes + + typedef i2p::data::Tag<32> SessionTag; class GarlicRoutingSession { public: - GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags); + GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags); + GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption ~GarlicRoutingSession (); - I2NPMessage * WrapSingleMessage (I2NPMessage * msg, const I2NPMessage * leaseSet); + I2NPMessage * WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet); int GetNextTag () const { return m_NextTag; }; uint32_t GetFirstMsgID () const { return m_FirstMsgID; }; @@ -60,12 +63,12 @@ namespace garlic private: - const i2p::data::RoutingDestination& m_Destination; + const i2p::data::RoutingDestination * m_Destination; uint8_t m_SessionKey[32]; uint32_t m_FirstMsgID; // first message ID bool m_IsAcknowledged; int m_NumTags, m_NextTag; - uint8_t * m_SessionTags; // m_NumTags*32 bytes + SessionTag * m_SessionTags; // m_NumTags*32 bytes uint32_t m_TagsCreationTime; // seconds since epoch i2p::crypto::CBCEncryption m_Encryption; @@ -74,6 +77,21 @@ namespace garlic class GarlicRouting { + class SessionDecryption: public i2p::crypto::CBCDecryption + { + public: + + SessionDecryption (): m_TagCount (0) {}; + void SetTagCount (int tagCount) { m_TagCount = tagCount; }; + void AddTagCount (int tagCount) { m_TagCount += tagCount; }; + int GetTagCount () const { return m_TagCount; }; + bool UseTag () { m_TagCount--; return m_TagCount > 0; }; + + private: + + int m_TagCount; + }; + public: GarlicRouting (); @@ -81,23 +99,24 @@ namespace garlic void Start (); void Stop (); - + void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag + void HandleGarlicMessage (I2NPMessage * msg); void HandleDeliveryStatusMessage (uint8_t * buf, size_t len); I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg); I2NPMessage * WrapMessage (const i2p::data::RoutingDestination& destination, - I2NPMessage * msg, const I2NPMessage * leaseSet = nullptr); + I2NPMessage * msg, I2NPMessage * leaseSet = nullptr); private: void Run (); void ProcessGarlicMessage (I2NPMessage * msg); - void HandleAESBlock (uint8_t * buf, size_t len, i2p::crypto::CBCDecryption * decryption); + void HandleAESBlock (uint8_t * buf, size_t len, SessionDecryption * decryption); void HandleGarlicPayload (uint8_t * buf, size_t len); private: - + bool m_IsRunning; std::thread * m_Thread; i2p::util::Queue m_Queue; @@ -105,8 +124,8 @@ namespace garlic std::map m_Sessions; std::map m_CreatedSessions; // msgID -> session // incoming session - std::list m_SessionDecryptions; // multiple tags refer to one decyption - std::map m_SessionTags; // tag -> decryption + // multiple tags refer to one decyption + std::map m_SessionTags; // tag -> decryption }; extern GarlicRouting routing; diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 038f6321..6d8d04b5 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -13,7 +13,7 @@ namespace i2p namespace util { - const std::string HTTPConnection::itoopieImage = + const std::string HTTPConnection::itoopieImage = "\"\""; - - namespace misc_strings + + namespace misc_strings { const char name_value_separator[] = { ':', ' ' }; @@ -146,7 +146,7 @@ namespace util buffers.push_back(boost::asio::buffer(misc_strings::crlf)); } buffers.push_back(boost::asio::buffer(misc_strings::crlf)); - } + } buffers.push_back(boost::asio::buffer(content)); return buffers; } @@ -154,9 +154,9 @@ namespace util void HTTPConnection::Terminate () { if (m_Stream) - { + { m_Stream->Close (); - DeleteStream (m_Stream); + DeleteStream (m_Stream); } m_Socket->close (); delete this; @@ -193,11 +193,11 @@ namespace util { b32 = address.substr (1, pos - 1); // excluding leading '/' to next '/' uri = address.substr (pos); // rest of line - } + } - HandleDestinationRequest (b32, uri); - } - else + HandleDestinationRequest (b32, uri); + } + else HandleRequest (); } @@ -209,10 +209,10 @@ namespace util char * http = strstr (get, "HTTP"); if (http) return std::string (get + 4, http - get - 5); - } + } return ""; - } - + } + void HTTPConnection::HandleWriteReply (const boost::system::error_code& ecode) { Terminate (); @@ -233,7 +233,7 @@ namespace util FillContent (s); s << ""; SendReply (s.str ()); - } + } void HTTPConnection::FillContent (std::stringstream& s) { @@ -241,7 +241,7 @@ namespace util s << "Our external address:" << "
"; for (auto& address : i2p::context.GetRouterInfo().GetAddresses()) { - switch (address.transportStyle) + switch (address.transportStyle) { case i2p::data::RouterInfo::eTransportNTCP: s << "NTCP  "; @@ -257,31 +257,31 @@ namespace util s << "
Routers: " << i2p::data::netdb.GetNumRouters () << " "; s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " "; s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "
"; - + s << "

Tunnels

"; for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ()) - { + { it->GetTunnelConfig ()->Print (s); if (it->GetTunnelPool () && !it->GetTunnelPool ()->IsExploratory ()) s << " " << "Pool"; if (it->IsFailed ()) s << " " << "Failed"; s << " " << (int)it->GetNumSentBytes () << "
"; - } + } for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ()) - { + { it.second->GetTunnelConfig ()->Print (s); if (it.second->GetTunnelPool () && !it.second->GetTunnelPool ()->IsExploratory ()) s << " " << "Pool"; if (it.second->IsFailed ()) s << " " << "Failed"; s << " " << (int)it.second->GetNumReceivedBytes () << "
"; - } - + } + s << "

Transit tunnels

"; for (auto it: i2p::tunnel::tunnels.GetTransitTunnels ()) - { + { if (dynamic_cast(it.second)) s << it.second->GetTunnelID () << "-->"; else if (dynamic_cast(it.second)) @@ -289,23 +289,24 @@ namespace util else s << "-->" << it.second->GetTunnelID () << "-->"; s << " " << it.second->GetNumTransmittedBytes () << "
"; - } + } s << "

Transports

"; s << "NTCP
"; for (auto it: i2p::transports.GetNTCPSessions ()) - { + { // RouterInfo of incoming connection doesn't have address bool outgoing = it.second->GetRemoteRouterInfo ().GetNTCPAddress (); if (it.second->IsEstablished ()) { if (outgoing) s << "-->"; - s << it.second->GetRemoteRouterInfo ().GetIdentHashAbbreviation () << ": " + s << it.second->GetRemoteRouterInfo ().GetIdentHashAbbreviation () << ": " << it.second->GetSocket ().remote_endpoint().address ().to_string (); if (!outgoing) s << "-->"; + s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; s << "
"; - } - } + } + } auto ssuServer = i2p::transports.GetSSUServer (); if (ssuServer) { @@ -318,14 +319,20 @@ namespace util if (outgoing) s << "-->"; s << endpoint.address ().to_string () << ":" << endpoint.port (); if (!outgoing) s << "-->"; + s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; s << "
"; - } - } + } + } s << "

Flibusta

"; - } - + } void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri) + { + HandleDestinationRequest(address, "GET", "", uri); + } + + void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& method, const std::string& data, const std::string& uri) { + const i2p::data::LeaseSet * leaseSet = nullptr; i2p::data::IdentHash destination; std::string fullAddress; if (address.find(".b32.i2p") != std::string::npos) @@ -354,17 +361,29 @@ namespace util } else { - if (i2p::data::Base32ToByteStream(address.c_str(), address.length(), (uint8_t *)destination, 32) != 32) + if (address == "local") { - LogPrint("Invalid Base32 address ", address); - SendReply("" + itoopieImage + "
Invalid Base32 address", 400); - return; + // TODO: remove later + fullAddress = "local.i2p"; + auto destination = i2p::stream::GetSharedLocalDestination (); + leaseSet = destination->GetLeaseSet (); + EepAccept (destination); } - fullAddress = address + ".b32.i2p"; + else + { + if (i2p::data::Base32ToByteStream(address.c_str(), address.length(), (uint8_t *)destination, 32) != 32) + { + LogPrint("Invalid Base32 address ", address); + SendReply("" + itoopieImage + "
Invalid Base32 address", 400); + return; + } + fullAddress = address + ".b32.i2p"; + } } } - - auto leaseSet = i2p::data::netdb.FindLeaseSet (destination); + + if (!leaseSet) + leaseSet = i2p::data::netdb.FindLeaseSet (destination); if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) { i2p::data::netdb.Subscribe(destination); @@ -374,23 +393,29 @@ namespace util { SendReply (leaseSet ? "" + itoopieImage + "
Leases expired" : "" + itoopieImage + "LeaseSet not found", 504); return; - } + } } - if (!m_Stream) + if (!m_Stream) m_Stream = i2p::stream::CreateStream (*leaseSet); if (m_Stream) { - std::string request = "GET " + uri + " HTTP/1.1\n Host:" + fullAddress + "\n"; - m_Stream->Send ((uint8_t *)request.c_str (), request.length (), 10); + std::string request = method+" " + uri + " HTTP/1.1\n Host:" + fullAddress + "\r\n"; + if (!strcmp(method.c_str(), "GET")) + { + // POST/PUT, apply body + request += "\r\n"+ data; + } + LogPrint("HTTP Client Request: ", request); + m_Stream->Send ((uint8_t *)request.c_str (), request.length (), 10); AsyncStreamReceive (); - } - } - + } + } + void HTTPConnection::AsyncStreamReceive () { if (m_Stream) m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192), - boost::bind (&HTTPConnection::HandleStreamReceive, this, + boost::bind (&HTTPConnection::HandleStreamReceive, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred), 45); // 45 seconds timeout } @@ -404,11 +429,11 @@ namespace util } else { - if (m_Stream && m_Stream->IsOpen ()) + if (ecode == boost::asio::error::timed_out) SendReply ("" + itoopieImage + "
Not responding", 504); - else + else Terminate (); - } + } } void HTTPConnection::SendReply (const std::string& content, int status) @@ -421,16 +446,16 @@ namespace util m_Reply.headers[1].value = "text/html"; boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status), - boost::bind (&HTTPConnection::HandleWriteReply, this, + boost::bind (&HTTPConnection::HandleWriteReply, this, boost::asio::placeholders::error)); } - - HTTPServer::HTTPServer (int port): - m_Thread (nullptr), m_Work (m_Service), + + HTTPServer::HTTPServer (int port): + m_Thread (nullptr), m_Work (m_Service), m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), m_NewSocket (nullptr) { - + } HTTPServer::~HTTPServer () @@ -450,17 +475,17 @@ namespace util m_Acceptor.close(); m_Service.stop (); if (m_Thread) - { - m_Thread->join (); + { + m_Thread->join (); delete m_Thread; m_Thread = nullptr; - } + } } void HTTPServer::Run () { m_Service.run (); - } + } void HTTPServer::Accept () { @@ -476,13 +501,55 @@ namespace util CreateConnection(m_NewSocket); // new HTTPConnection(m_NewSocket); Accept (); } - } + } void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket) { new HTTPConnection (m_NewSocket); } +// eepSite. TODO: move away + + void HTTPConnection::EepAccept (i2p::stream::StreamingDestination * destination) + { + if (destination) + destination->SetAcceptor (std::bind (&HTTPConnection::HandleEepAccept, this, std::placeholders::_1)); + } + + void HTTPConnection::HandleEepAccept (i2p::stream::Stream * stream) + { + if (stream) + { + auto conn = new EepSiteDummyConnection (stream); + conn->AsyncStreamReceive (); + } + } + + void EepSiteDummyConnection::AsyncStreamReceive () + { + if (m_Stream) + m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192), + boost::bind (&EepSiteDummyConnection::HandleStreamReceive, this, + boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred), + 60); // 60 seconds timeout + } + + void EepSiteDummyConnection::HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + { + LogPrint ("eepSite error: ", ecode.message ()); + DeleteStream (m_Stream); + } + else + { + std::string response ("HTTP/1.0 503 Not Implemented\r\n"); + m_Stream->Send ((uint8_t *)response.c_str (), response.length (), 30); + m_Stream->Close (); + } + delete this; + } + } } diff --git a/HTTPServer.h b/HTTPServer.h index cb594794..bef69bdf 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -14,13 +14,13 @@ namespace util class HTTPConnection { protected: - + struct header { std::string name; std::string value; }; - + struct request { std::string method; @@ -38,7 +38,7 @@ namespace util std::vector to_buffers (int status); }; - + public: HTTPConnection (boost::asio::ip::tcp::socket * socket): m_Socket (socket), m_Stream (nullptr) { Receive (); }; @@ -48,9 +48,9 @@ namespace util void Terminate (); void Receive (); - void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void AsyncStreamReceive (); - void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleWriteReply(const boost::system::error_code& ecode); void HandleWrite (const boost::system::error_code& ecode); void SendReply (const std::string& content, int status = 200); @@ -58,9 +58,13 @@ namespace util void HandleRequest (); void FillContent (std::stringstream& s); std::string ExtractAddress (); + + // for eepsite + void EepAccept (i2p::stream::StreamingDestination * destination); + void HandleEepAccept (i2p::stream::Stream * stream); protected: - + boost::asio::ip::tcp::socket * m_Socket; i2p::stream::Stream * m_Stream; char m_Buffer[8192], m_StreamBuffer[8192]; @@ -68,14 +72,16 @@ namespace util reply m_Reply; protected: - + + virtual void HandleDestinationRequest(const std::string& address, const std::string& uri); + virtual void HandleDestinationRequest(const std::string& address, const std::string& method, const std::string& data, const std::string& uri); virtual void RunRequest (); private: static const std::string itoopieImage; - }; + }; class HTTPServer { @@ -89,10 +95,10 @@ namespace util private: - void Run (); + void Run (); void Accept (); - void HandleAccept(const boost::system::error_code& ecode); - + void HandleAccept(const boost::system::error_code& ecode); + private: std::thread * m_Thread; @@ -103,7 +109,25 @@ namespace util protected: virtual void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket); - }; + }; + + // TODO: move away + class EepSiteDummyConnection + { + public: + + EepSiteDummyConnection (i2p::stream::Stream * stream): m_Stream (stream) {}; + void AsyncStreamReceive (); + + private: + + void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); + + private: + + i2p::stream::Stream * m_Stream; + char m_StreamBuffer[8192]; + }; } } diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 778d9197..7e1e78d7 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -1,4 +1,5 @@ #include +#include #include "I2PEndian.h" #include #include @@ -17,19 +18,25 @@ namespace i2p I2NPMessage * NewI2NPMessage () { - I2NPMessage * msg = new I2NPMessage; - msg->offset = 2; // reserve 2 bytes for NTCP header, should reserve more for SSU in future - msg->len = sizeof (I2NPHeader) + 2; - msg->from = nullptr; - return msg; + return new I2NPMessageBuffer(); } + I2NPMessage * NewI2NPShortMessage () + { + return new I2NPMessageBuffer(); + } + + I2NPMessage * NewI2NPMessage (size_t len) + { + return (len < I2NP_MAX_SHORT_MESSAGE_SIZE/2) ? NewI2NPShortMessage () : NewI2NPMessage (); + } + void DeleteI2NPMessage (I2NPMessage * msg) { delete msg; } - static uint32_t I2NPmsgID = 0; // TODO: create class + static std::atomic I2NPmsgID(0); // TODO: create class void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID) { I2NPHeader * header = msg->GetHeader (); @@ -62,7 +69,7 @@ namespace i2p I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID) { - I2NPMessage * msg = NewI2NPMessage (); + I2NPMessage * msg = NewI2NPMessage (len); memcpy (msg->GetPayload (), buf, len); msg->len += len; FillI2NPMessageHeader (msg, msgType, replyMsgID); @@ -94,7 +101,8 @@ namespace i2p } I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, - uint32_t replyTunnelID, bool exploratory, std::set * excludedPeers) + uint32_t replyTunnelID, bool exploratory, std::set * excludedPeers, + bool encryption) { I2NPMessage * m = NewI2NPMessage (); uint8_t * buf = m->GetPayload (); @@ -104,12 +112,13 @@ namespace i2p buf += 32; if (replyTunnelID) { - *buf = 0x01; // set delivery flag + *buf = encryption ? 0x03: 0x01; // set delivery flag *(uint32_t *)(buf+1) = htobe32 (replyTunnelID); buf += 5; } else { + encryption = false; // encryption can we set for tunnels only *buf = 0; // flag buf++; } @@ -142,58 +151,63 @@ namespace i2p buf += 2; } } + if (encryption) + { + // session key and tag for reply + auto& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (buf, 32); // key + buf[32] = 1; // 1 tag + rnd.GenerateBlock (buf + 33, 32); // tag + i2p::garlic::routing.AddSessionKey (buf, buf + 33); // introduce new key-tag to garlic engine + buf += 65; + } m->len += (buf - m->GetPayload ()); FillI2NPMessageHeader (m, eI2NPDatabaseLookup); return m; } - void HandleDatabaseLookupMsg (uint8_t * buf, size_t len) + I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, + const i2p::data::RouterInfo * floodfill) { - char key[48]; - int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); - key[l] = 0; - LogPrint ("DatabaseLookup for ", key, " recieved"); - uint8_t flag = buf[64]; - uint32_t replyTunnelID = 0; - if (flag & 0x01) //reply to yunnel - replyTunnelID = be32toh (*(uint32_t *)(buf + 64)); - // TODO: implement search. We send non-found for now - I2NPMessage * replyMsg = CreateDatabaseSearchReply (buf); - if (replyTunnelID) - i2p::tunnel::tunnels.GetNextOutboundTunnel ()->SendTunnelDataMsg (buf+32, replyTunnelID, replyMsg); - else - i2p::transports.SendMessage (buf, replyMsg); - } - - I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident) - { - I2NPMessage * m = NewI2NPMessage (); + I2NPMessage * m = NewI2NPShortMessage (); uint8_t * buf = m->GetPayload (); + size_t len = 0; memcpy (buf, ident, 32); - buf[32] = 0; // TODO: - memcpy (buf + 33, i2p::context.GetRouterInfo ().GetIdentHash (), 32); - m->len += 65; + len += 32; + buf[len] = floodfill ? 1 : 0; // 1 router for now + len++; + if (floodfill) + { + memcpy (buf + len, floodfill->GetIdentHash (), 32); + len += 32; + } + memcpy (buf + len, i2p::context.GetRouterInfo ().GetIdentHash (), 32); + len += 32; + m->len += len; FillI2NPMessageHeader (m, eI2NPDatabaseSearchReply); return m; } - I2NPMessage * CreateDatabaseStoreMsg () + I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::RouterInfo * router) { - I2NPMessage * m = NewI2NPMessage (); + if (!router) // we send own RouterInfo + router = &context.GetRouterInfo (); + + I2NPMessage * m = NewI2NPShortMessage (); I2NPDatabaseStoreMsg * msg = (I2NPDatabaseStoreMsg *)m->GetPayload (); - memcpy (msg->key, context.GetRouterInfo ().GetIdentHash (), 32); + memcpy (msg->key, router->GetIdentHash (), 32); msg->type = 0; msg->replyToken = 0; CryptoPP::Gzip compressor; - compressor.Put ((uint8_t *)context.GetRouterInfo ().GetBuffer (), context.GetRouterInfo ().GetBufferLen ()); + compressor.Put (router->GetBuffer (), router->GetBufferLen ()); compressor.MessageEnd(); - // WARNING!!! MaxRetrievable() return uint64_t. Есть подозрение, что что-то не так - int size = compressor.MaxRetrievable (); + auto size = compressor.MaxRetrievable (); uint8_t * buf = m->GetPayload () + sizeof (I2NPDatabaseStoreMsg); *(uint16_t *)buf = htobe16 (size); // size buf += 2; + // TODO: check if size doesn't exceed buffer compressor.Get (buf, size); m->len += sizeof (I2NPDatabaseStoreMsg) + 2 + size; // payload size FillI2NPMessageHeader (m, eI2NPDatabaseStore); @@ -201,6 +215,19 @@ namespace i2p return m; } + I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::LeaseSet * leaseSet) + { + if (!leaseSet) return nullptr; + I2NPMessage * m = NewI2NPShortMessage (); + I2NPDatabaseStoreMsg * msg = (I2NPDatabaseStoreMsg *)m->GetPayload (); + memcpy (msg->key, leaseSet->GetIdentHash (), 32); + msg->type = 1; // LeaseSet + msg->replyToken = 0; + memcpy (m->GetPayload () + sizeof (I2NPDatabaseStoreMsg), leaseSet->GetBuffer (), leaseSet->GetBufferLen ()); + m->len += leaseSet->GetBufferLen () + sizeof (I2NPDatabaseStoreMsg); + FillI2NPMessageHeader (m, eI2NPDatabaseStore); + return m; + } I2NPBuildRequestRecordClearText CreateBuildRequestRecord ( const uint8_t * ourIdent, uint32_t receiveTunnelID, @@ -346,6 +373,7 @@ namespace i2p else { LogPrint ("Outbound tunnel ", tunnel->GetTunnelID (), " has been declined"); + i2p::transports.CloseSession (tunnel->GetTunnelConfig ()->GetFirstHop ()->router); delete tunnel; } } @@ -375,7 +403,7 @@ namespace i2p I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len) { - I2NPMessage * msg = NewI2NPMessage (); + I2NPMessage * msg = NewI2NPMessage (len); TunnelGatewayHeader * header = (TunnelGatewayHeader *)msg->GetPayload (); header->tunnelID = htobe32 (tunnelID); header->length = htobe16 (len); @@ -410,7 +438,7 @@ namespace i2p I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID) { - I2NPMessage * msg = NewI2NPMessage (); + I2NPMessage * msg = NewI2NPMessage (len); size_t gatewayMsgOffset = sizeof (I2NPHeader) + sizeof (TunnelGatewayHeader); msg->offset += gatewayMsgOffset; msg->len += gatewayMsgOffset; @@ -435,6 +463,13 @@ namespace i2p msg->offset += sizeof (I2NPHeader) + sizeof (TunnelGatewayHeader); msg->len = msg->offset + len; LogPrint ("TunnelGateway of ", (int)len, " bytes for tunnel ", (unsigned int)tunnelID, ". Msg type ", (int)msg->GetHeader()->typeID); + if (msg->GetHeader()->typeID == eI2NPDatabaseStore) + { + // transit DatabaseStore my contain new/updated RI + auto ds = NewI2NPMessage (); + *ds = *msg; + i2p::data::netdb.PostI2NPMsg (ds); + } i2p::tunnel::TransitTunnel * tunnel = i2p::tunnel::tunnels.GetTransitTunnel (tunnelID); if (tunnel) tunnel->SendTunnelDataMsg (msg); @@ -477,10 +512,6 @@ namespace i2p LogPrint ("TunnelBuildReply"); // TODO: break; - case eI2NPDatabaseLookup: - LogPrint ("DatabaseLookup"); - HandleDatabaseLookupMsg (buf, size); - break; default: LogPrint ("Unexpected message ", (int)header->typeID); } @@ -505,13 +536,11 @@ namespace i2p i2p::garlic::routing.HandleGarlicMessage (msg); break; case eI2NPDatabaseStore: - LogPrint ("DatabaseStore"); - i2p::data::netdb.PostI2NPMsg (msg); - break; case eI2NPDatabaseSearchReply: - LogPrint ("DatabaseSearchReply"); + case eI2NPDatabaseLookup: + // forward to netDb i2p::data::netdb.PostI2NPMsg (msg); - break; + break; case eI2NPDeliveryStatus: LogPrint ("DeliveryStatus"); if (msg->from && msg->from->GetTunnelPool ()) diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 0b6e45d4..815cd7cf 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -6,6 +6,7 @@ #include #include "I2PEndian.h" #include "RouterInfo.h" +#include "LeaseSet.h" namespace i2p { @@ -100,13 +101,17 @@ namespace tunnel class InboundTunnel; } - const int NTCP_MAX_MESSAGE_SIZE = 16384; + const size_t I2NP_MAX_MESSAGE_SIZE = 32768; + const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 2400; struct I2NPMessage { - uint8_t buf[NTCP_MAX_MESSAGE_SIZE]; - size_t len, offset; + uint8_t * buf; + size_t len, offset, maxLen; i2p::tunnel::InboundTunnel * from; + I2NPMessage (): buf (nullptr),len (sizeof (I2NPHeader) + 2), + offset(2), maxLen (0), from (nullptr) {}; + // reserve 2 bytes for NTCP header I2NPHeader * GetHeader () { return (I2NPHeader *)GetBuffer (); }; uint8_t * GetPayload () { return GetBuffer () + sizeof(I2NPHeader); }; uint8_t * GetBuffer () { return buf + offset; }; @@ -143,7 +148,17 @@ namespace tunnel return be32toh (header.msgID); } }; + + template + struct I2NPMessageBuffer: public I2NPMessage + { + I2NPMessageBuffer () { buf = m_Buffer; maxLen = sz; }; + uint8_t m_Buffer[sz]; + }; + I2NPMessage * NewI2NPMessage (); + I2NPMessage * NewI2NPShortMessage (); + I2NPMessage * NewI2NPMessage (size_t len); void DeleteI2NPMessage (I2NPMessage * msg); void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID = 0); void RenewI2NPMessageHeader (I2NPMessage * msg); @@ -153,12 +168,12 @@ namespace tunnel I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID); I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, uint32_t replyTunnelID, bool exploratory = false, - std::set * excludedPeers = nullptr); - void HandleDatabaseLookupMsg (uint8_t * buf, size_t len); - I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident); - - I2NPMessage * CreateDatabaseStoreMsg (); + std::set * excludedPeers = nullptr, bool encryption = false); + I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, const i2p::data::RouterInfo * floodfill); + I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::RouterInfo * router = nullptr); + I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::LeaseSet * leaseSet); + I2NPBuildRequestRecordClearText CreateBuildRequestRecord ( const uint8_t * ourIdent, uint32_t receiveTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID, diff --git a/Identity.cpp b/Identity.cpp index 756eaec3..e63cdb35 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -16,20 +16,27 @@ namespace data { // copy public and signing keys together memcpy (publicKey, keys.publicKey, sizeof (publicKey) + sizeof (signingKey)); - memset (certificate, 0, sizeof (certificate)); + memset (&certificate, 0, sizeof (certificate)); return *this; } bool Identity::FromBase64 (const std::string& s) { - size_t count = Base64ToByteStream (s.c_str(), s.length(), publicKey, sizeof (Identity)); - return count == sizeof(Identity); + size_t count = Base64ToByteStream (s.c_str(), s.length(), publicKey, DEFAULT_IDENTITY_SIZE); + return count == DEFAULT_IDENTITY_SIZE; + } + + size_t Identity::FromBuffer (const uint8_t * buf, size_t len) + { + memcpy (publicKey, buf, DEFAULT_IDENTITY_SIZE); + // TODO: process certificate + return DEFAULT_IDENTITY_SIZE; } IdentHash Identity::Hash() const { IdentHash hash; - CryptoPP::SHA256().CalculateDigest(hash, publicKey, sizeof (Identity)); + CryptoPP::SHA256().CalculateDigest(hash, publicKey, DEFAULT_IDENTITY_SIZE); return hash; } @@ -40,11 +47,6 @@ namespace data return *this; } - bool IdentHash::FromBase32(const std::string& s) - { - size_t count = Base32ToByteStream(s.c_str(), s.length(), m_Hash, sizeof(m_Hash)); - return count == sizeof(m_Hash); - } Keys CreateRandomKeys () { diff --git a/Identity.h b/Identity.h index 9c91e9e6..ee76892b 100644 --- a/Identity.h +++ b/Identity.h @@ -3,13 +3,57 @@ #include #include +#include +#include "base64.h" #include "ElGamal.h" namespace i2p { namespace data { - class IdentHash; + template + class Tag + { + public: + + Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); }; + Tag (const Tag& ) = default; +#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it + Tag (Tag&& ) = default; +#endif + Tag () = default; + + Tag& operator= (const Tag& ) = default; +#ifndef _WIN32 + Tag& operator= (Tag&& ) = default; +#endif + + uint8_t * operator()() { return m_Buf; }; + const uint8_t * operator()() const { return m_Buf; }; + + operator uint8_t * () { return m_Buf; }; + operator const uint8_t * () const { return m_Buf; }; + + bool operator== (const Tag& other) const { return !memcmp (m_Buf, other.m_Buf, sz); }; + bool operator< (const Tag& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; }; + + std::string ToBase64 () const + { + char str[sz*2]; + int l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2); + str[l] = 0; + return std::string (str); + } + + private: + + union // 8 bytes alignment + { + uint8_t m_Buf[sz]; + uint64_t ll[sz/8]; + }; + }; + typedef Tag<32> IdentHash; #pragma pack(1) @@ -27,14 +71,28 @@ namespace data uint8_t signingKey[128]; }; + + const uint8_t CERTIFICATE_TYPE_NULL = 0; + const uint8_t CERTIFICATE_TYPE_HASHCASH = 1; + const uint8_t CERTIFICATE_TYPE_HIDDEN = 2; + const uint8_t CERTIFICATE_TYPE_SIGNED = 3; + const uint8_t CERTIFICATE_TYPE_MULTIPLE = 4; + const uint8_t CERTIFICATE_TYPE_KEY = 5; + + const size_t DEFAULT_IDENTITY_SIZE = 387; struct Identity { uint8_t publicKey[256]; uint8_t signingKey[128]; - uint8_t certificate[3]; + struct + { + uint8_t type; + uint16_t length; + } certificate; Identity& operator=(const Keys& keys); bool FromBase64(const std::string& ); + size_t FromBuffer (const uint8_t * buf, size_t len); IdentHash Hash() const; }; @@ -52,39 +110,7 @@ namespace data }; #pragma pack() - - class IdentHash - { - public: - - IdentHash (const uint8_t * hash) { memcpy (m_Hash, hash, 32); }; - IdentHash (const IdentHash& ) = default; -#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it - IdentHash (IdentHash&& ) = default; -#endif - IdentHash () = default; - - IdentHash& operator= (const IdentHash& ) = default; -#ifndef _WIN32 - IdentHash& operator= (IdentHash&& ) = default; -#endif - - uint8_t * operator()() { return m_Hash; }; - const uint8_t * operator()() const { return m_Hash; }; - - operator uint8_t * () { return m_Hash; }; - operator const uint8_t * () const { return m_Hash; }; - - bool operator== (const IdentHash& other) const { return !memcmp (m_Hash, other.m_Hash, 32); }; - bool operator< (const IdentHash& other) const { return memcmp (m_Hash, other.m_Hash, 32) < 0; }; - - bool FromBase32(const std::string&); - - private: - - uint8_t m_Hash[32]; - }; - + Keys CreateRandomKeys (); void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions @@ -141,9 +167,10 @@ namespace data virtual ~LocalDestination() {}; virtual const IdentHash& GetIdentHash () const = 0; + virtual const Identity& GetIdentity () const = 0; virtual const uint8_t * GetEncryptionPrivateKey () const = 0; virtual const uint8_t * GetEncryptionPublicKey () const = 0; - virtual void UpdateLeaseSet () = 0; // LeaseSet must be updated + virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0; }; } } diff --git a/LeaseSet.cpp b/LeaseSet.cpp index 7a7ebbc0..0b79a0ab 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -4,6 +4,7 @@ #include "Log.h" #include "Timestamp.h" #include "NetDb.h" +#include "TunnelPool.h" #include "LeaseSet.h" namespace i2p @@ -11,26 +12,64 @@ namespace i2p namespace data { - LeaseSet::LeaseSet (const uint8_t * buf, int len) + LeaseSet::LeaseSet (const uint8_t * buf, int len, bool unsolicited): + m_IsUnsolicited (unsolicited) { -#pragma pack(1) - struct H - { - Identity destination; - uint8_t encryptionKey[256]; - uint8_t signingKey[128]; - uint8_t num; - }; -#pragma pack () + memcpy (m_Buffer, buf, len); + m_BufferLen = len; + ReadFromBuffer (); + } - const H * header = (const H *)buf; + LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool): + m_IsUnsolicited (false) + { + m_BufferLen = 0; + // header + const i2p::data::LocalDestination& localDestination = pool.GetLocalDestination (); + LeaseSetHeader * header = (LeaseSetHeader *)m_Buffer; + header->destination = localDestination.GetIdentity (); + memcpy (header->encryptionKey, localDestination.GetEncryptionPublicKey (), 256); + memset (header->signingKey, 0, 128); + auto tunnels = pool.GetInboundTunnels (5); // 5 tunnels maximum + header->num = tunnels.size (); // num leases + m_BufferLen += sizeof (LeaseSetHeader); + // leases + for (auto it: tunnels) + { + Lease * lease = (Lease *)(m_Buffer + m_BufferLen); + memcpy (lease->tunnelGateway, it->GetNextIdentHash (), 32); + lease->tunnelID = htobe32 (it->GetNextTunnelID ()); + uint64_t ts = it->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - 60; // 1 minute before expiration + ts *= 1000; // in milliseconds + lease->endDate = htobe64 (ts); + m_BufferLen += sizeof (Lease); + } + // signature + localDestination.Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen); + m_BufferLen += 40; + LogPrint ("Local LeaseSet of ", tunnels.size (), " leases created"); + + ReadFromBuffer (); + } + + void LeaseSet::Update (const uint8_t * buf, int len) + { + m_Leases.clear (); + memcpy (m_Buffer, buf, len); + m_BufferLen = len; + ReadFromBuffer (); + } + + void LeaseSet::ReadFromBuffer () + { + const LeaseSetHeader * header = (const LeaseSetHeader *)m_Buffer; m_Identity = header->destination; m_IdentHash = m_Identity.Hash(); memcpy (m_EncryptionKey, header->encryptionKey, 256); LogPrint ("LeaseSet num=", (int)header->num); // process leases - const uint8_t * leases = buf + sizeof (H); + const uint8_t * leases = m_Buffer + sizeof (LeaseSetHeader); for (int i = 0; i < header->num; i++) { Lease lease = *(Lease *)leases; @@ -53,10 +92,10 @@ namespace data pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_Identity.signingKey, 128)); CryptoPP::DSA::Verifier verifier (pubKey); - if (!verifier.VerifyMessage (buf, leases - buf, leases, 40)) + if (!verifier.VerifyMessage (m_Buffer, leases - m_Buffer, leases, 40)) LogPrint ("LeaseSet verification failed"); - } - + } + const std::vector LeaseSet::GetNonExpiredLeases () const { auto ts = i2p::util::GetMillisecondsSinceEpoch (); diff --git a/LeaseSet.h b/LeaseSet.h index 9c805845..a8e70d43 100644 --- a/LeaseSet.h +++ b/LeaseSet.h @@ -8,6 +8,12 @@ namespace i2p { + +namespace tunnel +{ + class TunnelPool; +} + namespace data { @@ -28,16 +34,33 @@ namespace data } }; + struct LeaseSetHeader + { + Identity destination; + uint8_t encryptionKey[256]; + uint8_t signingKey[128]; + uint8_t num; + }; + #pragma pack() + const int MAX_LS_BUFFER_SIZE = 2048; class LeaseSet: public RoutingDestination { public: - LeaseSet (const uint8_t * buf, int len); + LeaseSet (const uint8_t * buf, int len, bool unsolicited = false); LeaseSet (const LeaseSet& ) = default; + LeaseSet (const i2p::tunnel::TunnelPool& pool); LeaseSet& operator=(const LeaseSet& ) = default; + void Update (const uint8_t * buf, int len); + const uint8_t * GetBuffer () const { return m_Buffer; }; + size_t GetBufferLen () const { return m_BufferLen; }; + + bool IsUnsolicited () const { return m_IsUnsolicited; }; + void SetUnsolicited (bool unsolicited) { m_IsUnsolicited = unsolicited; }; + // implements RoutingDestination const Identity& GetIdentity () const { return m_Identity; }; const IdentHash& GetIdentHash () const { return m_IdentHash; }; @@ -47,6 +70,10 @@ namespace data bool HasNonExpiredLeases () const; const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; }; bool IsDestination () const { return true; }; + + private: + + void ReadFromBuffer (); private: @@ -54,6 +81,9 @@ namespace data Identity m_Identity; IdentHash m_IdentHash; uint8_t m_EncryptionKey[256]; + uint8_t m_Buffer[MAX_LS_BUFFER_SIZE]; + size_t m_BufferLen; + bool m_IsUnsolicited; }; } } diff --git a/Log.cpp b/Log.cpp index 4a88f2ba..3f50d23a 100644 --- a/Log.cpp +++ b/Log.cpp @@ -1,12 +1,10 @@ #include "Log.h" -Log g_Log; +Log * g_Log = nullptr; void LogMsg::Process() { output << s.str(); - - std::cout << s.str (); // TODO: delete later } void Log::Flush () diff --git a/Log.h b/Log.h index f3e7ae53..9195ca03 100644 --- a/Log.h +++ b/Log.h @@ -37,7 +37,26 @@ class Log: public i2p::util::MsgQueue std::ofstream * m_LogFile; }; -extern Log g_Log; +extern Log * g_Log; + +inline void StartLog (const std::string& fullFilePath) +{ + if (!g_Log) + { + g_Log = new Log (); + if (fullFilePath.length () > 0) + g_Log->SetLogFile (fullFilePath); + } +} + +inline void StopLog () +{ + if (g_Log) + { + delete g_Log; + g_Log = nullptr; + } +} template void LogPrint (std::stringstream& s, TValue arg) @@ -55,10 +74,16 @@ void LogPrint (std::stringstream& s, TValue arg, TArgs... args) template void LogPrint (TArgs... args) { - LogMsg * msg = g_Log.GetLogFile () ? new LogMsg (*g_Log.GetLogFile ()) : new LogMsg (); + LogMsg * msg = (g_Log && g_Log->GetLogFile ()) ? new LogMsg (*g_Log->GetLogFile ()) : new LogMsg (); LogPrint (msg->s, args...); msg->s << std::endl; - g_Log.Put (msg); + if (g_Log) + g_Log->Put (msg); + else + { + msg->Process (); + delete msg; + } } #endif diff --git a/Makefile b/Makefile index 149ade28..8c426254 100644 --- a/Makefile +++ b/Makefile @@ -1,38 +1,9 @@ -CC = g++ -CFLAGS = -g -Wall -std=c++0x -OBJECTS = obj/CryptoConst.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/Reseed.o \ - obj/UPnP.o obj/TunnelPool.o obj/HTTPProxy.o obj/AddressBook.o obj/Daemon.o \ - obj/DaemonLinux.o obj/SSUData.o obj/i2p.o obj/aes.o -INCFLAGS = -LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread -LIBS = +UNAME := $(shell uname -s) -#check if AES-NI is supported by CPU -ifneq ($(shell grep -c aes /proc/cpuinfo),0) - CPU_FLAGS = -DAESNI +ifeq ($(UNAME),Darwin) + include Makefile.osx +else + include Makefile.linux endif -all: obj i2p - -i2p: $(OBJECTS:obj/%=obj/%) - $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) - -.SUFFIXES: -.SUFFIXES: .c .cc .C .cpp .o - -obj/%.o : %.cpp - $(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) $(CPU_FLAGS) - -obj: - mkdir -p obj - -clean: - rm -fr obj i2p - -.PHONY: all -.PHONY: clean - diff --git a/Makefile.linux b/Makefile.linux new file mode 100644 index 00000000..2ebc1889 --- /dev/null +++ b/Makefile.linux @@ -0,0 +1,33 @@ + +CC = g++ +CFLAGS = -g -Wall -std=c++0x +include filelist.mk +INCFLAGS = +LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread +LIBS = + +#check if AES-NI is supported by CPU +ifneq ($(shell grep -c aes /proc/cpuinfo),0) + CPU_FLAGS = -DAESNI +endif + +all: obj i2p + +i2p: $(OBJECTS:obj/%=obj/%) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) + +.SUFFIXES: +.SUFFIXES: .c .cc .C .cpp .o + +obj/%.o : %.cpp + $(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) $(CPU_FLAGS) + +obj: + mkdir -p obj + +clean: + rm -fr obj i2p + +.PHONY: all +.PHONY: clean + diff --git a/Makefile.osx b/Makefile.osx index e294971b..1c48d2a6 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -1,20 +1,15 @@ -#CC = clang++ -CC = g++ -CFLAGS = -g -Wall -std=c++11 -lstdc++ -OBJECTS = obj/CryptoConst.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/Reseed.o \ - obj/UPnP.o obj/TunnelPool.o obj/HTTPProxy.o obj/AddressBook.o obj/Daemon.o \ - obj/DaemonLinux.o obj/SSUData.o obj/i2p.o obj/aes.o +CC = clang++ +CFLAGS = -g -Wall -std=c++11 -lstdc++ -I/usr/local/include +include filelist.mk INCFLAGS = -DCRYPTOPP_DISABLE_ASM -LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread +LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LIBS = -#check if AES-NI is supported by CPU -ifneq ($(shell grep -c aes /proc/cpuinfo),0) - CPU_FLAGS = -DAESNI -endif +# OSX Notes +# http://www.hutsby.net/2011/08/macs-with-aes-ni.html +# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2 +# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic +CPU_FLAGS = -DAESNI # Apple Mac OSX UNAME_S := $(shell uname -s) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 9930dead..1d1f098a 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -21,7 +21,8 @@ namespace ntcp { NTCPSession::NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo): m_Socket (service), m_TerminationTimer (service), m_IsEstablished (false), - m_RemoteRouterInfo (in_RemoteRouterInfo), m_ReceiveBufferOffset (0), m_NextMessage (nullptr) + m_RemoteRouterInfo (in_RemoteRouterInfo), m_ReceiveBufferOffset (0), m_NextMessage (nullptr), + m_NumSentBytes (0), m_NumReceivedBytes (0) { m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); } @@ -402,7 +403,7 @@ namespace ntcp } else { - LogPrint ("Received: ", bytes_transferred); + m_NumReceivedBytes += bytes_transferred; m_ReceiveBufferOffset += bytes_transferred; if (m_ReceiveBufferOffset >= 16) @@ -513,7 +514,7 @@ namespace ntcp } else { - LogPrint ("Msg sent: ", bytes_transferred); + m_NumSentBytes += bytes_transferred; ScheduleTermination (); // reset termination timer } } diff --git a/NTCPSession.h b/NTCPSession.h index f453c417..1d03708b 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -62,6 +62,7 @@ namespace ntcp #pragma pack() + const size_t NTCP_MAX_MESSAGE_SIZE = 16384; const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes class NTCPSession { @@ -77,6 +78,9 @@ namespace ntcp void ClientLogin (); void ServerLogin (); void SendI2NPMessage (I2NPMessage * msg); + + size_t GetNumSentBytes () const { return m_NumSentBytes; }; + size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; protected: @@ -135,12 +139,14 @@ namespace ntcp NTCPPhase3 m_Phase3; NTCPPhase4 m_Phase4; - uint8_t m_ReceiveBuffer[i2p::NTCP_MAX_MESSAGE_SIZE*2], m_TimeSyncBuffer[16]; + uint8_t m_ReceiveBuffer[NTCP_MAX_MESSAGE_SIZE*2], m_TimeSyncBuffer[16]; int m_ReceiveBufferOffset; i2p::I2NPMessage * m_NextMessage; std::list m_DelayedMessages; size_t m_NextMessageOffset; + + size_t m_NumSentBytes, m_NumReceivedBytes; }; class NTCPClient: public NTCPSession diff --git a/NetDb.cpp b/NetDb.cpp index efd12c7c..81e7d984 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -23,12 +23,12 @@ namespace data const i2p::tunnel::InboundTunnel * replyTunnel) { I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination, - replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers); + replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers, m_IsLeaseSet); if (m_IsLeaseSet) // wrap lookup message into garlic msg = i2p::garlic::routing.WrapSingleMessage (*router, msg); m_ExcludedPeers.insert (router->GetIdentHash ()); m_LastRouter = router; - m_LastReplyTunnel = replyTunnel; + m_CreationTime = i2p::util::GetSecondsSinceEpoch (); return msg; } @@ -38,7 +38,7 @@ namespace data i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); m_ExcludedPeers.insert (floodfill); m_LastRouter = nullptr; - m_LastReplyTunnel = nullptr; + m_CreationTime = i2p::util::GetSecondsSinceEpoch (); return msg; } @@ -95,7 +95,7 @@ namespace data void NetDb::Run () { - uint32_t lastSave = 0, lastPublish = 0; + uint32_t lastSave = 0, lastPublish = 0, lastKeyspaceRotation = 0; m_IsRunning = true; while (m_IsRunning) { @@ -106,17 +106,24 @@ namespace data { while (msg) { - if (msg->GetHeader ()->typeID == eI2NPDatabaseStore) - { - HandleDatabaseStoreMsg (msg->GetPayload (), msg->GetLength ()); // TODO - i2p::DeleteI2NPMessage (msg); - } - else if (msg->GetHeader ()->typeID == eI2NPDatabaseSearchReply) - HandleDatabaseSearchReplyMsg (msg); - else // WTF? + switch (msg->GetHeader ()->typeID) { - LogPrint ("NetDb: unexpected message type ", msg->GetHeader ()->typeID); - i2p::HandleI2NPMessage (msg); + case eI2NPDatabaseStore: + LogPrint ("DatabaseStore"); + HandleDatabaseStoreMsg (msg->GetPayload (), msg->GetLength ()); // TODO + i2p::DeleteI2NPMessage (msg); + break; + case eI2NPDatabaseSearchReply: + LogPrint ("DatabaseSearchReply"); + HandleDatabaseSearchReplyMsg (msg); + break; + case eI2NPDatabaseLookup: + LogPrint ("DatabaseLookup"); + HandleDatabaseLookupMsg (msg); + break; + default: // WTF? + LogPrint ("NetDb: unexpected message type ", msg->GetHeader ()->typeID); + i2p::HandleI2NPMessage (msg); } msg = m_Queue.Get (); } @@ -128,11 +135,12 @@ namespace data } uint64_t ts = i2p::util::GetSecondsSinceEpoch (); - if (ts - lastSave >= 60) // save routers and validate subscriptions every minute + if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute { if (lastSave) { SaveUpdated (m_NetDbPath); + ManageLeaseSets (); ValidateSubscriptions (); } lastSave = ts; @@ -142,6 +150,11 @@ namespace data Publish (); lastPublish = ts; } + if (ts % 86400 < 60 && ts - lastKeyspaceRotation >= 60) // wihhin 1 minutes since midnight (86400 = 24*3600) + { + KeyspaceRotation (); + lastKeyspaceRotation = ts; + } } catch (std::exception& ex) { @@ -150,44 +163,40 @@ namespace data } } - void NetDb::AddRouterInfo (uint8_t * buf, int len) - { - RouterInfo * r = new RouterInfo (buf, len); - DeleteRequestedDestination (r->GetIdentHash ()); - auto it = m_RouterInfos.find(r->GetIdentHash ()); + void NetDb::AddRouterInfo (const IdentHash& ident, uint8_t * buf, int len) + { + DeleteRequestedDestination (ident); + auto it = m_RouterInfos.find(ident); if (it != m_RouterInfos.end ()) { - if (r->GetTimestamp () > it->second->GetTimestamp ()) - { + auto ts = it->second->GetTimestamp (); + it->second->Update (buf, len); + if (it->second->GetTimestamp () > ts) LogPrint ("RouterInfo updated"); - *(it->second) = *r; // we can't replace pointer because it's used by tunnels - } - delete r; } else { LogPrint ("New RouterInfo added"); + RouterInfo * r = new RouterInfo (buf, len); m_RouterInfos[r->GetIdentHash ()] = r; if (r->IsFloodfill ()) m_Floodfills.push_back (r); } } - void NetDb::AddLeaseSet (uint8_t * buf, int len) + void NetDb::AddLeaseSet (const IdentHash& ident, uint8_t * buf, int len) { - LeaseSet * l = new LeaseSet (buf, len); - DeleteRequestedDestination (l->GetIdentHash ()); - auto it = m_LeaseSets.find(l->GetIdentHash ()); + bool unsolicited = !DeleteRequestedDestination (ident); + auto it = m_LeaseSets.find(ident); if (it != m_LeaseSets.end ()) { + it->second->Update (buf, len); LogPrint ("LeaseSet updated"); - *(it->second) = *l; // we can't replace pointer because it's used by streams - delete l; } else { LogPrint ("New LeaseSet added"); - m_LeaseSets[l->GetIdentHash ()] = l; + m_LeaseSets[ident] = new LeaseSet (buf, len, unsolicited); } } @@ -259,14 +268,25 @@ namespace data for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1) { #if BOOST_VERSION > 10500 - RouterInfo * r = new RouterInfo (it1->path().string().c_str ()); + const std::string& fullPath = it1->path().string(); #else - RouterInfo * r = new RouterInfo(it1->path().c_str()); + const std::string& fullPath = it1->path(); #endif - m_RouterInfos[r->GetIdentHash ()] = r; - if (r->IsFloodfill ()) - m_Floodfills.push_back (r); - numRouters++; + RouterInfo * r = new RouterInfo(fullPath); + if (!r->IsUnreachable ()) + { + r->DeleteBuffer (); + m_RouterInfos[r->GetIdentHash ()] = r; + if (r->IsFloodfill ()) + m_Floodfills.push_back (r); + numRouters++; + } + else + { + if (boost::filesystem::exists (fullPath)) + boost::filesystem::remove (fullPath); + delete r; + } } } } @@ -302,9 +322,9 @@ namespace data { if (it.second->IsUpdated ()) { - std::ofstream r (GetFilePath(fullDirectory, it.second), std::ofstream::binary); - r.write ((char *)it.second->GetBuffer (), it.second->GetBufferLen ()); + it.second->SaveToFile (GetFilePath(fullDirectory, it.second)); it.second->SetUpdated (false); + it.second->DeleteBuffer (); count++; } else @@ -362,7 +382,6 @@ namespace data if (msgs.size () > 0) { dest->ClearExcludedPeers (); - dest->SetLastOutboundTunnel (outbound); outbound->SendTunnelDataMsg (msgs); } else @@ -379,10 +398,7 @@ namespace data RequestedDestination * dest = CreateRequestedDestination (destination, false); auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ()); if (floodfill) - { - dest->SetLastOutboundTunnel (nullptr); i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); - } } } @@ -395,7 +411,7 @@ namespace data if (msg->type) { LogPrint ("LeaseSet"); - AddLeaseSet (buf + offset, len - offset); + AddLeaseSet (msg->key, buf + offset, len - offset); } else { @@ -413,7 +429,7 @@ namespace data uint8_t uncompressed[2048]; size_t uncomressedSize = decompressor.MaxRetrievable (); decompressor.Get (uncompressed, uncomressedSize); - AddRouterInfo (uncompressed, uncomressedSize); + AddRouterInfo (msg->key, uncompressed, uncomressedSize); } } @@ -429,10 +445,12 @@ namespace data if (it != m_RequestedDestinations.end ()) { RequestedDestination * dest = it->second; + bool deleteDest = true; if (num > 0) { - i2p::tunnel::OutboundTunnel * outbound = dest->GetLastOutboundTunnel (); - const i2p::tunnel::InboundTunnel * inbound = dest->GetLastReplyTunnel (); + auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool (); + auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr; + auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr; std::vector msgs; for (int i = 0; i < num; i++) @@ -450,11 +468,10 @@ namespace data { // router with ident not found or too old (1 hour) LogPrint ("Found new/outdated router. Requesting RouterInfo ..."); - if (outbound && inbound) + if (outbound && inbound && dest->GetLastRouter ()) { RequestedDestination * d1 = CreateRequestedDestination (router, false, false); - d1->SetLastOutboundTunnel (outbound); - auto msg = d1->CreateRequestMessage (dest->GetLastRouter (), dest->GetLastReplyTunnel ()); + auto msg = d1->CreateRequestMessage (dest->GetLastRouter (), inbound); msgs.push_back (i2p::tunnel::TunnelMessageBlock { i2p::tunnel::eDeliveryTypeRouter, @@ -468,7 +485,7 @@ namespace data else { // reply to our destination. Try other floodfills - if (outbound && inbound) + if (outbound && inbound && dest->GetLastRouter ()) { auto r = FindRouter (router); // do we have that floodfill router in our database? @@ -477,6 +494,7 @@ namespace data // we do if (!dest->IsExcluded (r->GetIdentHash ()) && dest->GetNumExcludedPeers () < 30) // TODO: fix TunnelGateway first { + LogPrint ("Try ", key, " at floodfill ", peerHash); // tell floodfill about us msgs.push_back (i2p::tunnel::TunnelMessageBlock { @@ -485,12 +503,13 @@ namespace data CreateDatabaseStoreMsg () }); // request destination - auto msg = dest->CreateRequestMessage (r, dest->GetLastReplyTunnel ()); + auto msg = dest->CreateRequestMessage (r, inbound); msgs.push_back (i2p::tunnel::TunnelMessageBlock { i2p::tunnel::eDeliveryTypeRouter, r->GetIdentHash (), 0, msg }); + deleteDest = false; } } else @@ -498,7 +517,6 @@ namespace data // request router LogPrint ("Found new floodfill. Request it"); RequestedDestination * d2 = CreateRequestedDestination (router, false, false); - d2->SetLastOutboundTunnel (outbound); I2NPMessage * msg = d2->CreateRequestMessage (dest->GetLastRouter (), inbound); msgs.push_back (i2p::tunnel::TunnelMessageBlock { @@ -512,16 +530,26 @@ namespace data if (!dest->IsLeaseSet ()) // if not LeaseSet { if (!dest->IsExcluded (router) && dest->GetNumExcludedPeers () < 30) + { + LogPrint ("Try ", key, " at floodfill ", peerHash, " directly"); i2p::transports.SendMessage (router, dest->CreateRequestMessage (router)); + deleteDest = false; + } } else LogPrint ("Can't request LeaseSet"); } - } + } } if (outbound && msgs.size () > 0) outbound->SendTunnelDataMsg (msgs); + if (deleteDest) + { + // no more requests for tha destinationation. delete it + delete it->second; + m_RequestedDestinations.erase (it); + } } else { @@ -535,8 +563,104 @@ namespace data i2p::DeleteI2NPMessage (msg); } + void NetDb::HandleDatabaseLookupMsg (I2NPMessage * msg) + { + uint8_t * buf = msg->GetPayload (); + char key[48]; + int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); + key[l] = 0; + LogPrint ("DatabaseLookup for ", key, " recieved"); + uint8_t flag = buf[64]; + uint8_t * excluded = buf + 65; + uint32_t replyTunnelID = 0; + if (flag & 0x01) //reply to tunnel + { + replyTunnelID = be32toh (*(uint32_t *)(buf + 64)); + excluded += 4; + } + uint16_t numExcluded = be16toh (*(uint16_t *)excluded); + excluded += 2; + if (numExcluded > 512) + { + LogPrint ("Number of excluded peers", numExcluded, " exceeds 512"); + numExcluded = 0; // TODO: + } + + I2NPMessage * replyMsg = nullptr; + + { + auto router = FindRouter (buf); + if (router) + { + LogPrint ("Requested RouterInfo ", key, " found"); + router->LoadBuffer (); + if (router->GetBuffer ()) + replyMsg = CreateDatabaseStoreMsg (router); + } + } + if (!replyMsg) + { + auto leaseSet = FindLeaseSet (buf); + if (leaseSet && leaseSet->IsUnsolicited ()) // we don't send back our LeaseSets + { + LogPrint ("Requested LeaseSet ", key, " found"); + replyMsg = CreateDatabaseStoreMsg (leaseSet); + } + } + if (!replyMsg) + { + LogPrint ("Requested ", key, " not found. ", numExcluded, " excluded"); + std::set excludedRouters; + for (int i = 0; i < numExcluded; i++) + { + // TODO: check for all zeroes (exploratory) + excludedRouters.insert (excluded); + excluded += 32; + } + replyMsg = CreateDatabaseSearchReply (buf, GetClosestFloodfill (buf, excludedRouters)); + } + else + excluded += numExcluded*32; // we don't care about exluded + + if (replyMsg) + { + if (replyTunnelID) + { + // encryption might be used though tunnel only + if (flag & 0x02) // encrypted reply requested + { + uint8_t * sessionKey = excluded; + uint8_t numTags = sessionKey[32]; + if (numTags > 0) + { + uint8_t * sessionTag = sessionKey + 33; // take first tag + i2p::garlic::GarlicRoutingSession garlic (sessionKey, sessionTag); + replyMsg = garlic.WrapSingleMessage (replyMsg, nullptr); + } + } + i2p::tunnel::tunnels.GetNextOutboundTunnel ()->SendTunnelDataMsg (buf+32, replyTunnelID, replyMsg); + } + else + i2p::transports.SendMessage (buf, replyMsg); + } + i2p::DeleteI2NPMessage (msg); + } + void NetDb::Explore (int numDestinations) { + // clean up previous exploratories + uint64_t ts = i2p::util::GetSecondsSinceEpoch (); + for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();) + { + if (it->second->IsExploratory () || ts > it->second->GetCreationTime () + 60) // no response for 1 minute + { + delete it->second; + it = m_RequestedDestinations.erase (it); + } + else + it++; + } + // new requests auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool (); auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr; auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr; @@ -557,7 +681,6 @@ namespace data floodfills.insert (floodfill); if (throughTunnels) { - dest->SetLastOutboundTunnel (outbound); msgs.push_back (i2p::tunnel::TunnelMessageBlock { i2p::tunnel::eDeliveryTypeRouter, @@ -572,11 +695,7 @@ namespace data }); } else - { - dest->SetLastOutboundTunnel (nullptr); - dest->SetLastReplyTunnel (nullptr); i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); - } } else DeleteRequestedDestination (dest); @@ -614,14 +733,16 @@ namespace data return it->second; } - void NetDb::DeleteRequestedDestination (const IdentHash& dest) + bool NetDb::DeleteRequestedDestination (const IdentHash& dest) { auto it = m_RequestedDestinations.find (dest); if (it != m_RequestedDestinations.end ()) { delete it->second; m_RequestedDestinations.erase (it); + return true; } + return false; } void NetDb::DeleteRequestedDestination (RequestedDestination * dest) @@ -692,6 +813,8 @@ namespace data LogPrint ("LeaseSet requested"); RequestDestination (ident, true); } + else + leaseSet->SetUnsolicited (false); m_Subscriptions.insert (ident); } @@ -712,5 +835,28 @@ namespace data } } } + + void NetDb::KeyspaceRotation () + { + for (auto it: m_RouterInfos) + it.second->UpdateRoutingKey (); + LogPrint ("Keyspace rotation complete"); + Publish (); + } + + void NetDb::ManageLeaseSets () + { + for (auto it = m_LeaseSets.begin (); it != m_LeaseSets.end ();) + { + if (it->second->IsUnsolicited () && !it->second->HasNonExpiredLeases ()) // all leases expired + { + LogPrint ("LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired"); + delete it->second; + it = m_LeaseSets.erase (it); + } + else + it++; + } + } } } diff --git a/NetDb.h b/NetDb.h index d9451f7c..95c692ca 100644 --- a/NetDb.h +++ b/NetDb.h @@ -25,32 +25,27 @@ namespace data RequestedDestination (const IdentHash& destination, bool isLeaseSet, bool isExploratory = false): m_Destination (destination), m_IsLeaseSet (isLeaseSet), m_IsExploratory (isExploratory), - m_LastRouter (nullptr), m_LastReplyTunnel (nullptr), m_LastOutboundTunnel (nullptr) {}; + m_LastRouter (nullptr), m_CreationTime (0) {}; const IdentHash& GetDestination () const { return m_Destination; }; int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); }; const std::set& GetExcludedPeers () { return m_ExcludedPeers; }; void ClearExcludedPeers (); const RouterInfo * GetLastRouter () const { return m_LastRouter; }; - const i2p::tunnel::InboundTunnel * GetLastReplyTunnel () const { return m_LastReplyTunnel; }; - void SetLastReplyTunnel (i2p::tunnel::InboundTunnel * tunnel) { m_LastReplyTunnel = tunnel; }; bool IsExploratory () const { return m_IsExploratory; }; bool IsLeaseSet () const { return m_IsLeaseSet; }; bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); }; + uint64_t GetCreationTime () const { return m_CreationTime; }; I2NPMessage * CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel); I2NPMessage * CreateRequestMessage (const IdentHash& floodfill); - - i2p::tunnel::OutboundTunnel * GetLastOutboundTunnel () const { return m_LastOutboundTunnel; }; - void SetLastOutboundTunnel (i2p::tunnel::OutboundTunnel * tunnel) { m_LastOutboundTunnel = tunnel; }; - + private: IdentHash m_Destination; bool m_IsLeaseSet, m_IsExploratory; std::set m_ExcludedPeers; const RouterInfo * m_LastRouter; - const i2p::tunnel::InboundTunnel * m_LastReplyTunnel; - i2p::tunnel::OutboundTunnel * m_LastOutboundTunnel; + uint64_t m_CreationTime; }; class NetDb @@ -63,8 +58,8 @@ namespace data void Start (); void Stop (); - void AddRouterInfo (uint8_t * buf, int len); - void AddLeaseSet (uint8_t * buf, int len); + void AddRouterInfo (const IdentHash& ident, uint8_t * buf, int len); + void AddLeaseSet (const IdentHash& ident, uint8_t * buf, int len); RouterInfo * FindRouter (const IdentHash& ident) const; LeaseSet * FindLeaseSet (const IdentHash& destination) const; const IdentHash * FindAddress (const std::string& address) { return m_AddressBook.FindAddress (address); }; // TODO: move AddressBook away from NetDb @@ -75,7 +70,8 @@ namespace data void HandleDatabaseStoreMsg (uint8_t * buf, size_t len); void HandleDatabaseSearchReplyMsg (I2NPMessage * msg); - + void HandleDatabaseLookupMsg (I2NPMessage * msg); + const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith = nullptr) const; void PostI2NPMsg (I2NPMessage * msg); @@ -95,12 +91,14 @@ namespace data void Publish (); void ValidateSubscriptions (); const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set& excluded) const; + void KeyspaceRotation (); + void ManageLeaseSets (); RequestedDestination * CreateRequestedDestination (const IdentHash& dest, bool isLeaseSet, bool isExploratory = false); - void DeleteRequestedDestination (const IdentHash& dest); + bool DeleteRequestedDestination (const IdentHash& dest); // returns true if found void DeleteRequestedDestination (RequestedDestination * dest); - + private: std::map m_LeaseSets; diff --git a/Queue.h b/Queue.h index 22f51e69..8cc5440e 100644 --- a/Queue.h +++ b/Queue.h @@ -65,7 +65,7 @@ namespace util return m_Queue.empty (); } - void WakeUp () { m_NonEmpty.notify_one (); }; + void WakeUp () { m_NonEmpty.notify_all (); }; Element * Get () { @@ -108,11 +108,15 @@ namespace util typedef std::function OnEmpty; MsgQueue (): m_IsRunning (true), m_Thread (std::bind (&MsgQueue::Run, this)) {}; + ~MsgQueue () { Stop (); }; void Stop() { - m_IsRunning = false; - Queue::WakeUp (); - m_Thread.join(); + if (m_IsRunning) + { + m_IsRunning = false; + Queue::WakeUp (); + m_Thread.join(); + } } void SetOnEmpty (OnEmpty const & e) { m_OnEmpty = e; }; diff --git a/README.md b/README.md index 2a393e85..2daa7beb 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,13 @@ on Windows Requires msvs2013, boost 1.46 and higher, crypto++ -[![Build Status](https://travis-ci.org/orignal/i2pd.svg?branch=master)](https://travis-ci.org/orignal/i2pd) +Build Statuses +--------------- + +- Linux x64 - [![Build Status](https://jenkins.nordcloud.no/buildStatus/icon?job=i2pd-linux)](https://jenkins.nordcloud.no/job/i2pd-linux/) +- Linux ARM - Too be added +- Mac OS X - Too be added +- Microsoft VC13 - Too be added Testing diff --git a/Reseed.cpp b/Reseed.cpp index e60ffa44..e68f313c 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -19,11 +19,25 @@ namespace data "http://cowpuncher.drollette.com/netdb/", "http://i2p.mooo.com/netDb/", "http://reseed.info/", - "http://reseed.pkol.de/", "http://uk.reseed.i2p2.no/", + "http://us.reseed.i2p2.no/", + "http://jp.reseed.i2p2.no/", "http://i2p-netdb.innovatio.no/", "http://ieb9oopo.mooo.com" - }; + }; + + //TODO: Remember to add custom port support. Not all serves on 443 + static std::vector httpsReseedHostList = { + "https://193.150.121.66/netDb/", + "https://netdb.i2p2.no/", + "https://reseed.i2p-projekt.de/", + "https://cowpuncher.drollette.com/netdb/", + "https://i2p.mooo.com/netDb/", + "https://reseed.info/", + "https://i2p-netdb.innovatio.no/", + "https://ieb9oopo.mooo.com/", + "https://ssl.webpack.de/ivae2he9.sg4.e-plaza.de/" // Only HTTPS and SU3 (v2) support + }; //TODO: Implement v2 reseeding. Lightweight zip library is needed. //TODO: Implement SU3, utils. @@ -39,6 +53,15 @@ namespace data { try { + // Seems like the best place to try to intercept with SSL + /*ssl_server = true; + try { + // SSL + } + catch (std::exception& e) + { + LogPrint("Exception in SSL: ", e.what()); + }*/ std::string reseedHost = httpReseedHostList[(rand() % httpReseedHostList.size())]; LogPrint("Reseeding from ", reseedHost); std::string content = i2p::util::http::httpRequest(reseedHost); @@ -56,7 +79,7 @@ namespace data std::string routerInfo; std::string tmpUrl; std::string filename; - std::string ignoreFileSuffix = ".zip"; + std::string ignoreFileSuffix = ".su3"; boost::filesystem::path root = i2p::util::filesystem::GetDataDir(); while (i != j) { diff --git a/RouterContext.cpp b/RouterContext.cpp index bde075ad..f9f684ef 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -34,13 +34,13 @@ namespace i2p routerInfo.AddSSUAddress ("127.0.0.1", 17007, routerInfo.GetIdentHash ()); routerInfo.AddNTCPAddress ("127.0.0.1", 17007); // TODO: routerInfo.SetProperty ("caps", "LR"); - routerInfo.SetProperty ("coreVersion", "0.9.8.1"); + routerInfo.SetProperty ("coreVersion", "0.9.11"); routerInfo.SetProperty ("netId", "2"); - routerInfo.SetProperty ("router.version", "0.9.8.1"); + routerInfo.SetProperty ("router.version", "0.9.11"); routerInfo.SetProperty ("start_uptime", "90m"); routerInfo.CreateBuffer (); - m_RouterInfo = routerInfo; + m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); } void RouterContext::OverrideNTCPAddress (const char * host, int port) @@ -64,10 +64,10 @@ namespace i2p m_RouterInfo.CreateBuffer (); } - void RouterContext::Sign (uint8_t * buf, int len, uint8_t * signature) + void RouterContext::Sign (const uint8_t * buf, int len, uint8_t * signature) const { CryptoPP::DSA::Signer signer (m_SigningPrivateKey); - signer.SignMessage (m_Rnd, buf, len, signature); + signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, len, signature); } bool RouterContext::Load () @@ -79,7 +79,8 @@ namespace i2p m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); - m_RouterInfo = i2p::data::RouterInfo (i2p::util::filesystem::GetFullPath (ROUTER_INFO).c_str ()); // TODO + i2p::data::RouterInfo routerInfo(i2p::util::filesystem::GetFullPath (ROUTER_INFO)); // TODO + m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); return true; } @@ -92,7 +93,6 @@ namespace i2p fk.write ((char *)&m_Keys, sizeof (m_Keys)); } - std::ofstream fi (i2p::util::filesystem::GetFullPath (ROUTER_INFO).c_str (), std::ofstream::binary | std::ofstream::out); - fi.write ((char *)m_RouterInfo.GetBuffer (), m_RouterInfo.GetBufferLen ()); + m_RouterInfo.SaveToFile (i2p::util::filesystem::GetFullPath (ROUTER_INFO)); } } diff --git a/RouterContext.h b/RouterContext.h index bd5acd4e..5e7a8858 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -23,17 +23,16 @@ namespace i2p const uint8_t * GetSigningPrivateKey () const { return m_Keys.signingPrivateKey; }; const i2p::data::Identity& GetRouterIdentity () const { return m_RouterInfo.GetRouterIdentity (); }; CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator () { return m_Rnd; }; - - 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 // implements LocalDestination - void UpdateLeaseSet () {}; const i2p::data::IdentHash& GetIdentHash () const { return m_RouterInfo.GetIdentHash (); }; + const i2p::data::Identity& GetIdentity () const { return GetRouterIdentity (); }; const uint8_t * GetEncryptionPrivateKey () const { return GetPrivateKey (); }; const uint8_t * GetEncryptionPublicKey () const { return m_Keys.publicKey; }; + void Sign (const uint8_t * buf, int len, uint8_t * signature) const; private: diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 9ffe7edf..3976e9b1 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -17,52 +17,87 @@ namespace i2p { namespace data { - RouterInfo::RouterInfo (const char * filename): - m_IsUpdated (false), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0) + RouterInfo::RouterInfo (const std::string& fullPath): + m_FullPath (fullPath), m_IsUpdated (false), m_IsUnreachable (false), + m_SupportedTransports (0), m_Caps (0) { - ReadFromFile (filename); + m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; + ReadFromFile (); } RouterInfo::RouterInfo (const uint8_t * buf, int len): m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0) { + m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; memcpy (m_Buffer, buf, len); m_BufferLen = len; ReadFromBuffer (); } - + + RouterInfo::~RouterInfo () + { + delete m_Buffer; + } + + void RouterInfo::Update (const uint8_t * buf, int len) + { + if (!m_Buffer) + m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; + m_IsUpdated = true; + m_IsUnreachable = false; + m_SupportedTransports = 0; + m_Caps = 0; + m_Addresses.clear (); + m_Properties.clear (); + memcpy (m_Buffer, buf, len); + m_BufferLen = len; + ReadFromBuffer (); + // don't delete buffer until save to file + } + void RouterInfo::SetRouterIdentity (const Identity& identity) { m_RouterIdentity = identity; - m_IdentHash = m_RouterIdentity.Hash (); + m_IdentHash = m_RouterIdentity.Hash (); UpdateIdentHashBase64 (); UpdateRoutingKey (); m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); } - void RouterInfo::ReadFromFile (const char * filename) + bool RouterInfo::LoadFile () { - std::ifstream s(filename, std::ifstream::binary); + std::ifstream s(m_FullPath.c_str (), std::ifstream::binary); if (s.is_open ()) { s.seekg (0,std::ios::end); m_BufferLen = s.tellg (); if (m_BufferLen < 40) { - LogPrint("File", filename, " is malformed"); - return; + LogPrint("File", m_FullPath, " is malformed"); + return false; } s.seekg(0, std::ios::beg); - s.read(m_Buffer,m_BufferLen); - ReadFromBuffer (); + if (!m_Buffer) + m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; + s.read((char *)m_Buffer, m_BufferLen); } else - LogPrint ("Can't open file ", filename); + { + LogPrint ("Can't open file ", m_FullPath); + return false; + } + return true; + } + + void RouterInfo::ReadFromFile () + { + if (LoadFile ()) + ReadFromBuffer (); } void RouterInfo::ReadFromBuffer () { - std::stringstream str (std::string (m_Buffer, m_BufferLen)); + std::stringstream str (std::string ((char *)m_Buffer, m_BufferLen)); ReadFromStream (str); // verify signature CryptoPP::DSA::PublicKey pubKey; @@ -83,8 +118,10 @@ namespace data // read addresses uint8_t numAddresses; s.read ((char *)&numAddresses, sizeof (numAddresses)); + bool introducers = false; for (int i = 0; i < numAddresses; i++) { + bool isValidAddress = true; Address address; s.read ((char *)&address.cost, sizeof (address.cost)); s.read ((char *)&address.date, sizeof (address.date)); @@ -114,7 +151,7 @@ namespace data { // TODO: we should try to resolve address here LogPrint ("Unexpected address ", value); - SetUnreachable (true); + isValidAddress = false; } else { @@ -134,6 +171,7 @@ namespace data else if (key[0] == 'i') { // introducers + introducers = true; size_t l = strlen(key); unsigned char index = key[l-1] - '0'; // TODO: key[l-1] = 0; @@ -153,7 +191,8 @@ namespace data Base64ToByteStream (value, strlen (value), introducer.iKey, 32); } } - m_Addresses.push_back(address); + if (isValidAddress) + m_Addresses.push_back(address); } // read peers uint8_t numPeers; @@ -187,7 +226,7 @@ namespace data UpdateIdentHashBase64 (); UpdateRoutingKey (); - if (!m_SupportedTransports) + if (!m_SupportedTransports || !m_Addresses.size() || (UsesIntroducer () && !introducers)) SetUnreachable (true); } @@ -311,17 +350,41 @@ namespace data s.write (properties.str ().c_str (), properties.str ().size ()); } + const uint8_t * RouterInfo::LoadBuffer () + { + if (!m_Buffer) + { + if (LoadFile ()) + LogPrint ("Buffer for ", m_IdentHashAbbreviation, " loaded from file"); + } + return m_Buffer; + } + void RouterInfo::CreateBuffer () { m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); // refresh timstamp std::stringstream s; WriteToStream (s); m_BufferLen = s.str ().size (); + if (!m_Buffer) + m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; memcpy (m_Buffer, s.str ().c_str (), m_BufferLen); // signature i2p::context.Sign ((uint8_t *)m_Buffer, m_BufferLen, (uint8_t *)m_Buffer + m_BufferLen); m_BufferLen += 40; } + + void RouterInfo::SaveToFile (const std::string& fullPath) + { + m_FullPath = fullPath; + if (m_Buffer) + { + std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out); + f.write ((char *)m_Buffer, m_BufferLen); + } + else + LogPrint ("Can't save to file"); + } size_t RouterInfo::ReadString (char * str, std::istream& s) { diff --git a/RouterInfo.h b/RouterInfo.h index 9ce9b006..cc50b7c9 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -13,6 +13,7 @@ namespace i2p { namespace data { + const int MAX_RI_BUFFER_SIZE = 2048; class RouterInfo: public RoutingDestination { public: @@ -62,11 +63,12 @@ namespace data std::vector introducers; }; - RouterInfo (const char * filename); - RouterInfo () = default; + RouterInfo (const std::string& fullPath); + RouterInfo (): m_Buffer (nullptr) { m_IdentHashBase64[0] = 0; m_IdentHashAbbreviation[0] = 0; }; RouterInfo (const RouterInfo& ) = default; RouterInfo& operator=(const RouterInfo& ) = default; RouterInfo (const uint8_t * buf, int len); + ~RouterInfo (); const Identity& GetRouterIdentity () const { return m_RouterIdentity; }; void SetRouterIdentity (const Identity& identity); @@ -95,23 +97,31 @@ namespace data void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; bool IsUnreachable () const { return m_IsUnreachable; }; - + + const uint8_t * GetBuffer () const { return m_Buffer; }; + const uint8_t * LoadBuffer (); // load if necessary + int GetBufferLen () const { return m_BufferLen; }; + void CreateBuffer (); void UpdateRoutingKey (); - const char * GetBuffer () const { return m_Buffer; }; - int GetBufferLen () const { return m_BufferLen; }; bool IsUpdated () const { return m_IsUpdated; }; void SetUpdated (bool updated) { m_IsUpdated = updated; }; + void SaveToFile (const std::string& fullPath); + void Update (const uint8_t * buf, int len); + void DeleteBuffer () { delete m_Buffer; m_Buffer = nullptr; }; + // implements RoutingDestination const IdentHash& GetIdentHash () const { return m_IdentHash; }; const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity.publicKey; }; bool IsDestination () const { return false; }; + private: - void ReadFromFile (const char * filename); + bool LoadFile (); + void ReadFromFile (); void ReadFromStream (std::istream& s); void ReadFromBuffer (); void WriteToStream (std::ostream& s); @@ -123,11 +133,12 @@ namespace data private: + std::string m_FullPath; Identity m_RouterIdentity; IdentHash m_IdentHash; RoutingKey m_RoutingKey; char m_IdentHashBase64[48], m_IdentHashAbbreviation[5]; - char m_Buffer[2048]; + uint8_t * m_Buffer; int m_BufferLen; uint64_t m_Timestamp; std::vector
m_Addresses; diff --git a/SOCKS.cpp b/SOCKS.cpp new file mode 100644 index 00000000..7243a8d8 --- /dev/null +++ b/SOCKS.cpp @@ -0,0 +1,282 @@ +#include "SOCKS.h" +#include "Identity.h" +#include "NetDb.h" +#include +#include +#include +#include + +namespace i2p +{ +namespace proxy +{ + constexpr uint8_t socks_leaseset_timeout = 10; + constexpr uint8_t socks_timeout = 60; + + void SOCKS4AHandler::AsyncSockRead() + { + LogPrint("--- socks4a async sock read"); + if(m_sock) { + if (m_state == INITIAL) { + m_sock->async_receive(boost::asio::buffer(m_sock_buff, socks_buffer_size), + boost::bind(&SOCKS4AHandler::HandleSockRecv, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } else { + m_sock->async_receive(boost::asio::buffer(m_sock_buff, socks_buffer_size), + boost::bind(&SOCKS4AHandler::HandleSockForward, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + } else { + LogPrint("--- socks4a no socket for read"); + } + } + + void SOCKS4AHandler::AsyncStreamRead() + { + + LogPrint("--- socks4a async stream read"); + if (m_stream) { + m_stream->AsyncReceive( + boost::asio::buffer(m_stream_buff, socks_buffer_size), + boost::bind(&SOCKS4AHandler::HandleStreamRecv, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred), socks_timeout); + } else { + LogPrint("--- socks4a no stream for read"); + } + } + + void SOCKS4AHandler::Terminate() { + CloseStream(); + CloseSock(); + delete this; // ew + } + + void SOCKS4AHandler::SocksFailed() + { + LogPrint("--- socks4a failed"); + m_sock->send(boost::asio::buffer("\x00\x5b 12345")); + Terminate(); + } + + void SOCKS4AHandler::CloseSock() + { + if (m_sock) { + LogPrint("--- socks4a close sock"); + m_sock->close(); + delete m_sock; + m_sock = nullptr; + } + } + + void SOCKS4AHandler::CloseStream() + { + if (m_stream) { + LogPrint("--- socks4a close stream"); + delete m_stream; + m_stream = nullptr; + } + } + + constexpr size_t socks_hostname_size = 1024; + constexpr size_t socks_ident_size = 1024; + constexpr size_t destb32_len = 52; + + void SOCKS4AHandler::HandleSockForward(const boost::system::error_code & ecode, std::size_t len) + { + if(ecode) { + LogPrint("--- socks4a forward got error: ", ecode); + Terminate(); + return; + } + + LogPrint("--- socks4a sock forward: ", len); + m_stream->Send(m_sock_buff, len, 1); + } + + void SOCKS4AHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len) + { + LogPrint("--- socks4a sock recv: ", len); + + if(ecode) { + LogPrint(" --- sock recv got error: ", ecode); + Terminate(); + return; + } + + if (m_state == INITIAL) { + + char hostbuff[socks_hostname_size]; + char identbuff[socks_ident_size]; + std::memset(hostbuff, 0, sizeof(hostbuff)); + std::memset(identbuff, 0, sizeof(hostbuff)); + std::string dest; + // get port + uint16_t port = 0; + uint16_t idx1 = 0; + uint16_t idx2 = 0; + + LogPrint("--- socks4a state initial ", len); + + // check valid request + if( m_sock_buff[0] != 4 || m_sock_buff[1] != 1 || m_sock_buff[len-1] ) { + LogPrint("--- socks4a rejected invalid"); + SocksFailed(); + return; + } + + // get port + port = m_sock_buff[3] | m_sock_buff[2] << 8; + + // read ident + do { + LogPrint("--- socks4a ", (int) m_sock_buff[9+idx1]); + identbuff[idx1] = m_sock_buff[8+idx1]; + } while( identbuff[idx1++] && idx1 < socks_ident_size ); + + LogPrint("--- socks4a ident ", identbuff); + // read hostname + do { + hostbuff[idx2] = m_sock_buff[8+idx1+idx2]; + } while( hostbuff[idx2++] && idx2 < socks_hostname_size ); + + LogPrint("--- socks4a requested ", hostbuff, ":" , port); + + dest = std::string(hostbuff); + if(dest.find(".b32.i2p") == std::string::npos) { + LogPrint("--- socks4a invalid hostname: ", dest); + SocksFailed(); + return; + } + + if ( i2p::data::Base32ToByteStream(hostbuff, destb32_len, (uint8_t *) m_dest, 32) != 32 ) { + LogPrint("--- sock4a invalid b32: ", dest); + } + + LogPrint("--- sock4a find lease set"); + m_ls = i2p::data::netdb.FindLeaseSet(m_dest); + if (!m_ls || m_ls->HasNonExpiredLeases()) { + i2p::data::netdb.Subscribe(m_dest); + m_ls_timer.expires_from_now(boost::posix_time::seconds(socks_leaseset_timeout)); + m_ls_timer.async_wait(boost::bind(&SOCKS4AHandler::LeaseSetTimeout, this, boost::asio::placeholders::error)); + } else { + ConnectionSuccess(); + } + } else { + LogPrint("--- socks4a state?? ", m_state); + } + } + + void SOCKS4AHandler::HandleStreamRecv(const boost::system::error_code & ecode, std::size_t len) + { + if(ecode) { LogPrint("--- socks4a stream recv error: ", ecode); m_state = END; } + switch(m_state) { + case INITIAL: + case END: + Terminate(); + return; + case OKAY: + LogPrint("--- socks4a stream recv ", len); + boost::asio::async_write(*m_sock, boost::asio::buffer(m_stream_buff, len), + boost::bind(&SOCKS4AHandler::StreamWrote, this, + boost::asio::placeholders::error)); + } + } + + void SOCKS4AHandler::SockWrote(const boost::system::error_code & ecode) + { + LogPrint("--- socks4a sock wrote"); + if(ecode) { LogPrint("--- socks4a SockWrote error: ",ecode); } + else { AsyncSockRead(); } + } + + void SOCKS4AHandler::StreamWrote(const boost::system::error_code & ecode) + { + + LogPrint("--- socks4a stream wrote"); + if(ecode) { LogPrint("--- socks4a StreamWrote error: ",ecode); } + else { AsyncStreamRead(); } + } + + void SOCKS4AHandler::LeaseSetTimeout(const boost::system::error_code & ecode) + { + m_ls = i2p::data::netdb.FindLeaseSet(m_dest); + if(m_ls) { + ConnectionSuccess(); + } else { + LogPrint("--- socks4a ls timeout"); + SocksFailed(); + } + } + + void SOCKS4AHandler::ConnectionSuccess() + { + LogPrint("--- socks4a connection success"); + boost::asio::async_write(*m_sock, boost::asio::buffer("\x00\x5a 12345"), + boost::bind(&SOCKS4AHandler::SentConnectionSuccess, this, + boost::asio::placeholders::error)); + } + + void SOCKS4AHandler::SentConnectionSuccess(const boost::system::error_code & ecode) + { + LogPrint("--- socks4a making connection"); + m_stream = i2p::stream::CreateStream(*m_ls); + m_state = OKAY; + LogPrint("--- socks4a state is ", m_state); + AsyncSockRead(); + AsyncStreamRead(); + } + + void SOCKS4AServer::Run() + { + LogPrint("--- socks4a run"); + m_run = true; + while(m_run) { + try { + m_ios.run(); + } catch (std::runtime_error & exc) { + LogPrint("--- socks4a exception: ", exc.what()); + } + } + } + + void SOCKS4AServer::Accept() + { + m_new_sock = new boost::asio::ip::tcp::socket(m_ios); + m_acceptor.async_accept(*m_new_sock, + boost::bind( + &SOCKS4AServer::HandleAccept, this, boost::asio::placeholders::error)); + } + + void SOCKS4AServer::Start() + { + m_run = true; + m_thread = new std::thread(std::bind(&SOCKS4AServer::Run, this)); + m_acceptor.listen(); + Accept(); + } + + void SOCKS4AServer::Stop() + { + m_acceptor.close(); + m_run = false; + m_ios.stop(); + if (m_thread) { + m_thread->join(); + delete m_thread; + m_thread = nullptr; + } + } + + void SOCKS4AServer::HandleAccept(const boost::system::error_code & ecode) + { + if (!ecode) { + LogPrint("--- socks4a accepted"); + new SOCKS4AHandler(&m_ios, m_new_sock); + Accept(); + } + } +} +} diff --git a/SOCKS.h b/SOCKS.h new file mode 100644 index 00000000..af9e4788 --- /dev/null +++ b/SOCKS.h @@ -0,0 +1,98 @@ +#ifndef SOCKS4A_H__ +#define SOCKS4A_H__ + +#include +#include +#include +#include + +#include "Identity.h" +#include "Streaming.h" + +namespace i2p +{ +namespace proxy +{ + + constexpr size_t socks_buffer_size = 8192; + + class SOCKS4AHandler { + + private: + enum state { + INITIAL, + OKAY, + END + }; + + void GotClientRequest(boost::system::error_code & ecode, std::string & host, uint16_t port); + void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); + void HandleSockForward(const boost::system::error_code & ecode, std::size_t bytes_transfered); + void HandleStreamRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); + void Terminate(); + void CloseSock(); + void CloseStream(); + void AsyncSockRead(); + void AsyncStreamRead(); + void SocksFailed(); + void LeaseSetTimeout(const boost::system::error_code & ecode); + void StreamWrote(const boost::system::error_code & ecode); + void SockWrote(const boost::system::error_code & ecode); + void SentConnectionSuccess(const boost::system::error_code & ecode); + void ConnectionSuccess(); + + uint8_t m_sock_buff[socks_buffer_size]; + uint8_t m_stream_buff[socks_buffer_size]; + + boost::asio::io_service * m_ios; + boost::asio::ip::tcp::socket * m_sock; + boost::asio::deadline_timer m_ls_timer; + i2p::stream::Stream * m_stream; + i2p::data::LeaseSet * m_ls; + i2p::data::IdentHash m_dest; + state m_state; + + + public: + SOCKS4AHandler(boost::asio::io_service * ios, boost::asio::ip::tcp::socket * sock) : + m_ios(ios), m_sock(sock), m_ls_timer(*ios), + m_stream(nullptr), m_ls(nullptr), m_state(INITIAL) { AsyncSockRead(); } + + ~SOCKS4AHandler() { CloseSock(); CloseStream(); } + bool isComplete() { return m_state == END; } + }; + + class SOCKS4AServer { + public: + SOCKS4AServer(int port) : m_run(false), + m_thread(nullptr), + m_work(m_ios), + m_acceptor(m_ios, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)), + m_new_sock(nullptr) { } + ~SOCKS4AServer() { Stop(); } + void Start(); + void Stop(); + + + private: + + void Run(); + void Accept(); + void HandleAccept(const boost::system::error_code& ecode); + + bool m_run; + std::thread * m_thread; + boost::asio::io_service m_ios; + boost::asio::io_service::work m_work; + boost::asio::ip::tcp::acceptor m_acceptor; + boost::asio::ip::tcp::socket * m_new_sock; + + + }; + + typedef SOCKS4AServer SOCKSProxy; +} +} + + +#endif diff --git a/SSU.cpp b/SSU.cpp index c7b180ef..0765ef24 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -19,7 +19,8 @@ namespace ssu const i2p::data::RouterInfo * router, bool peerTest ): m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router), m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_State (eSessionStateUnknown), - m_IsSessionKey (false), m_RelayTag (0), m_Data (*this) + m_IsSessionKey (false), m_RelayTag (0), m_Data (*this), + m_NumSentBytes (0), m_NumReceivedBytes (0) { m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); } @@ -74,20 +75,18 @@ namespace ssu void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { + m_NumReceivedBytes += len; if (m_State == eSessionStateIntroduced) { // HolePunch received - LogPrint ("SSU HolePuch of ", len, " bytes received"); + LogPrint ("SSU HolePunch of ", len, " bytes received"); m_State = eSessionStateUnknown; Connect (); } else { - ScheduleTermination (); - // check for duplicate - const uint8_t * iv = ((SSUHeader *)buf)->iv; - if (m_ReceivedIVs.count (iv)) return; // duplicate detected - m_ReceivedIVs.insert (iv); + if (m_State == eSessionStateEstablished) + ScheduleTermination (); if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first DecryptSessionKey (buf, len); @@ -151,7 +150,8 @@ namespace ssu } case PAYLOAD_TYPE_RELAY_RESPONSE: ProcessRelayResponse (buf, len); - m_Server.DeleteSession (this); + if (m_State != eSessionStateEstablished) + m_Server.DeleteSession (this); break; case PAYLOAD_TYPE_RELAY_REQUEST: LogPrint ("SSU relay request received"); @@ -626,7 +626,7 @@ namespace ssu if (!m_DelayedMessages.empty ()) { for (auto it :m_DelayedMessages) - delete it; + DeleteI2NPMessage (it); m_DelayedMessages.clear (); } } @@ -651,7 +651,6 @@ namespace ssu if (m_State != eSessionStateFailed) { m_State = eSessionStateFailed; - Close (); m_Server.DeleteSession (this); // delete this } } @@ -821,6 +820,7 @@ namespace ssu // encrypt message with session key FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48); Send (buf, 48); + LogPrint ("SSU session destoryed sent"); } } @@ -841,6 +841,7 @@ namespace ssu void SSUSession::Send (const uint8_t * buf, size_t size) { + m_NumSentBytes += size; m_Server.Send (buf, size, m_RemoteEndpoint); } @@ -909,7 +910,6 @@ namespace ssu void SSUServer::Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to) { m_Socket.send_to (boost::asio::buffer (buf, len), to); - LogPrint ("SSU sent ", len, " bytes"); } void SSUServer::Receive () @@ -922,7 +922,6 @@ namespace ssu { if (!ecode) { - LogPrint ("SSU received ", bytes_transferred, " bytes"); SSUSession * session = nullptr; auto it = m_Sessions.find (m_SenderEndpoint); if (it != m_Sessions.end ()) @@ -985,30 +984,46 @@ namespace ssu else { // connect through introducer - session->WaitForIntroduction (); - if (address->introducers.size () > 0) + int numIntroducers = address->introducers.size (); + if (numIntroducers > 0) { - auto& introducer = address->introducers[0]; // TODO: - boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort); - LogPrint ("Creating new SSU session to [", router->GetIdentHashAbbreviation (), - "] through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ()); - it = m_Sessions.find (introducerEndpoint); SSUSession * introducerSession = nullptr; - if (it != m_Sessions.end ()) + const i2p::data::RouterInfo::Introducer * introducer = nullptr; + // we might have a session to introducer already + for (int i = 0; i < numIntroducers; i++) { - LogPrint ("Session to introducer already exists"); - introducerSession = it->second; - } - else - { - LogPrint ("New session to introducer created"); - introducerSession = new SSUSession (*this, introducerEndpoint, router); - m_Sessions[introducerEndpoint] = introducerSession; + introducer = &(address->introducers[i]); + it = m_Sessions.find (boost::asio::ip::udp::endpoint (introducer->iHost, introducer->iPort)); + if (it != m_Sessions.end ()) + { + introducerSession = it->second; + break; + } } - introducerSession->Introduce (introducer.iTag, introducer.iKey); + + if (introducerSession) // session found + LogPrint ("Session to introducer already exists"); + else // create new + { + LogPrint ("Creating new session to introducer"); + introducer = &(address->introducers[0]); // TODO: + boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort); + introducerSession = new SSUSession (*this, introducerEndpoint, router); + m_Sessions[introducerEndpoint] = introducerSession; + } + // introduce + LogPrint ("Introduce new SSU session to [", router->GetIdentHashAbbreviation (), + "] through introducer ", introducer->iHost, ":", introducer->iPort); + session->WaitForIntroduction (); + introducerSession->Introduce (introducer->iTag, introducer->iKey); } else - LogPrint ("Router is unreachable, but not introducers presentd. Ignored"); + { + LogPrint ("Router is unreachable, but no introducers presented. Ignored"); + m_Sessions.erase (remoteEndpoint); + delete session; + session = nullptr; + } } } } diff --git a/SSU.h b/SSU.h index b0930370..d5d4ebc3 100644 --- a/SSU.h +++ b/SSU.h @@ -31,7 +31,6 @@ namespace ssu }; #pragma pack() - const size_t SSU_MTU = 1484; const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes @@ -74,7 +73,10 @@ namespace ssu void SendPeerTest (); // Alice SessionState GetState () const { return m_State; }; - + size_t GetNumSentBytes () const { return m_NumSentBytes; }; + size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; + + private: void CreateAESandMacKey (const uint8_t * pubKey); @@ -113,21 +115,7 @@ namespace ssu void HandleTerminationTimer (const boost::system::error_code& ecode); private: - - union IV - { - uint8_t buf[16]; - uint64_t ll[2]; - - IV (const IV&) = default; - IV (const uint8_t * iv) { memcpy (buf, iv, 16); }; - bool operator< (const IV& other) const - { - if (ll[0] != other.ll[0]) return ll[0] < other.ll[0]; - return ll[1] < other.ll[1]; - }; - }; - + friend class SSUData; // TODO: change in later SSUServer& m_Server; boost::asio::ip::udp::endpoint m_RemoteEndpoint; @@ -143,8 +131,8 @@ namespace ssu i2p::crypto::CBCDecryption m_SessionKeyDecryption; uint8_t m_SessionKey[32], m_MacKey[32]; std::list m_DelayedMessages; - std::set m_ReceivedIVs; SSUData m_Data; + size_t m_NumSentBytes, m_NumReceivedBytes; }; class SSUServer diff --git a/SSUData.cpp b/SSUData.cpp index e363a2bf..a99d8999 100644 --- a/SSUData.cpp +++ b/SSUData.cpp @@ -1,4 +1,7 @@ +#include +#include #include "Log.h" +#include "Timestamp.h" #include "SSU.h" #include "SSUData.h" @@ -7,7 +10,7 @@ namespace i2p namespace ssu { SSUData::SSUData (SSUSession& session): - m_Session (session) + m_Session (session), m_ResendTimer (session.m_Server.GetService ()) { } @@ -20,10 +23,7 @@ namespace ssu delete it.second; } for (auto it: m_SentMessages) - { - for (auto f: it.second) - delete[] f; - } + delete it.second; } void SSUData::ProcessSentMessageAck (uint32_t msgID) @@ -31,19 +31,15 @@ namespace ssu auto it = m_SentMessages.find (msgID); if (it != m_SentMessages.end ()) { - // delete all ack-ed message's fragments - for (auto f: it->second) - delete[] f; + delete it->second; m_SentMessages.erase (it); + if (m_SentMessages.empty ()) + m_ResendTimer.cancel (); } } - void SSUData::ProcessMessage (uint8_t * buf, size_t len) + void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag) { - //uint8_t * start = buf; - uint8_t flag = *buf; - buf++; - LogPrint ("Process SSU data flags=", (int)flag); if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED) { // explicit ACKs @@ -60,13 +56,45 @@ namespace ssu buf++; for (int i = 0; i < numBitfields; i++) { + uint32_t msgID = be32toh (*(uint32_t *)buf); buf += 4; // msgID - // TODO: process individual Ack bitfields - while (*buf & 0x80) // not last + auto it = m_SentMessages.find (msgID); + // process individual Ack bitfields + bool isNonLast = false; + int fragment = 0; + do + { + uint8_t bitfield = *buf; + isNonLast = bitfield & 0x80; + bitfield &= 0x7F; // clear MSB + if (bitfield && it != m_SentMessages.end ()) + { + int numSentFragments = it->second->fragments.size (); + // process bits + uint8_t mask = 0x40; + for (int j = 0; j < 7; j++) + { + if (bitfield & mask) + { + if (fragment < numSentFragments) + { + delete it->second->fragments[fragment]; + it->second->fragments[fragment] = nullptr; + } + } + fragment++; + mask >>= 1; + } + } buf++; - buf++; // last byte + } + while (isNonLast); } - } + } + } + + void SSUData::ProcessFragments (uint8_t * buf) + { uint8_t numFragments = *buf; // number of fragments buf++; for (int i = 0; i < numFragments; i++) @@ -82,81 +110,140 @@ namespace ssu bool isLast = fragmentInfo & 0x010000; // bit 16 uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17 LogPrint ("SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last"); - I2NPMessage * msg = nullptr; - if (fragmentNum > 0) // follow-up fragment - { - auto it = m_IncomleteMessages.find (msgID); - if (it != m_IncomleteMessages.end ()) - { - if (fragmentNum == it->second->nextFragmentNum) - { - // expected fragment - msg = it->second->msg; - memcpy (msg->buf + msg->len, buf, fragmentSize); - msg->len += fragmentSize; - it->second->nextFragmentNum++; - } - else if (fragmentNum < it->second->nextFragmentNum) - // duplicate fragment - LogPrint ("Duplicate fragment ", fragmentNum, " of message ", msgID, ". Ignored"); - else - { - // missing fragment - LogPrint ("Missing fragments from ", it->second->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID); - //TODO - } - - if (isLast) - { - if (!msg) - DeleteI2NPMessage (it->second->msg); - delete it->second; - m_IncomleteMessages.erase (it); - } - } - else - // TODO: - LogPrint ("Unexpected follow-on fragment ", fragmentNum, " of message ", msgID); - } - else // first fragment - { - msg = NewI2NPMessage (); - memcpy (msg->GetSSUHeader (), buf, fragmentSize); - msg->len += fragmentSize - sizeof (I2NPHeaderShort); - } - if (msg) - { - if (!fragmentNum && !isLast) - m_IncomleteMessages[msgID] = new IncompleteMessage (msg); - if (isLast) + // find message with msgID + I2NPMessage * msg = nullptr; + IncompleteMessage * incompleteMessage = nullptr; + auto it = m_IncomleteMessages.find (msgID); + if (it != m_IncomleteMessages.end ()) + { + // message exists + incompleteMessage = it->second; + msg = incompleteMessage->msg; + } + else + { + // create new message + msg = NewI2NPMessage (); + msg->len -= sizeof (I2NPHeaderShort); + incompleteMessage = new IncompleteMessage (msg); + m_IncomleteMessages[msgID] = incompleteMessage; + } + + // handle current fragment + if (fragmentNum == incompleteMessage->nextFragmentNum) + { + // expected fragment + memcpy (msg->buf + msg->len, buf, fragmentSize); + msg->len += fragmentSize; + incompleteMessage->nextFragmentNum++; + if (!isLast && !incompleteMessage->savedFragments.empty ()) { - SendMsgAck (msgID); - msg->FromSSU (msgID); - if (m_Session.GetState () == eSessionStateEstablished) - i2p::HandleI2NPMessage (msg); - else + // try saved fragments + for (auto it1 = incompleteMessage->savedFragments.begin (); it1 != incompleteMessage->savedFragments.end ();) { - // we expect DeliveryStatus - if (msg->GetHeader ()->typeID == eI2NPDeliveryStatus) + auto savedFragment = *it1; + if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum) { - LogPrint ("SSU session established"); - m_Session.Established (); - } + memcpy (msg->buf + msg->len, savedFragment->buf, savedFragment->len); + msg->len += savedFragment->len; + isLast = savedFragment->isLast; + incompleteMessage->nextFragmentNum++; + incompleteMessage->savedFragments.erase (it1++); + delete savedFragment; + } else - LogPrint ("SSU unexpected message ", (int)msg->GetHeader ()->typeID); - DeleteI2NPMessage (msg); + break; + } + if (isLast) + LogPrint ("Message ", msgID, " complete"); + } + } + else + { + if (fragmentNum < incompleteMessage->nextFragmentNum) + // duplicate fragment + LogPrint ("Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ". Ignored"); + else + { + // missing fragment + LogPrint ("Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID); + auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast); + if (!incompleteMessage->savedFragments.insert (savedFragment).second) + { + LogPrint ("Fragment ", (int)fragmentNum, " of message ", msgID, " already saved"); + delete savedFragment; } } - } + isLast = false; + } + + if (isLast) + { + // delete incomplete message + delete incompleteMessage; + m_IncomleteMessages.erase (msgID); + // process message + SendMsgAck (msgID); + msg->FromSSU (msgID); + if (m_Session.GetState () == eSessionStateEstablished) + i2p::HandleI2NPMessage (msg); + else + { + // we expect DeliveryStatus + if (msg->GetHeader ()->typeID == eI2NPDeliveryStatus) + { + LogPrint ("SSU session established"); + m_Session.Established (); + } + else + LogPrint ("SSU unexpected message ", (int)msg->GetHeader ()->typeID); + DeleteI2NPMessage (msg); + } + } + else + SendFragmentAck (msgID, fragmentNum); buf += fragmentSize; } } + void SSUData::ProcessMessage (uint8_t * buf, size_t len) + { + //uint8_t * start = buf; + uint8_t flag = *buf; + buf++; + LogPrint ("Process SSU data flags=", (int)flag); + // process acks if presented + if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED)) + ProcessAcks (buf, flag); + // extended data if presented + if (flag & DATA_FLAG_EXTENDED_DATA_INCLUDED) + { + uint8_t extendedDataSize = *buf; + buf++; // size + LogPrint ("SSU extended data of ", extendedDataSize, " bytes presented"); + buf += extendedDataSize; + } + // process data + ProcessFragments (buf); + } + void SSUData::Send (i2p::I2NPMessage * msg) { uint32_t msgID = msg->ToSSU (); - auto fragments = m_SentMessages[msgID]; + if (m_SentMessages.count (msgID) > 0) + { + LogPrint ("SSU message ", msgID, " already sent"); + DeleteI2NPMessage (msg); + return; + } + if (m_SentMessages.empty ()) // schedule resend at first message only + ScheduleResend (); + SentMessage * sentMessage = new SentMessage; + m_SentMessages[msgID] = sentMessage; + sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL; + sentMessage->numResends = 0; + auto& fragments = sentMessage->fragments; msgID = htobe32 (msgID); size_t payloadSize = SSU_MTU - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3) size_t len = msg->GetLength (); @@ -165,8 +252,9 @@ namespace ssu uint32_t fragmentNum = 0; while (len > 0) { - uint8_t * buf = new uint8_t[SSU_MTU + 18]; - fragments.push_back (buf); + Fragment * fragment = new Fragment; + uint8_t * buf = fragment->buf; + fragments.push_back (fragment); uint8_t * payload = buf + sizeof (SSUHeader); *payload = DATA_FLAG_WANT_REPLY; // for compatibility payload++; @@ -189,6 +277,7 @@ namespace ssu size += payload - buf; if (size & 0x0F) // make sure 16 bytes boundary size = ((size >> 4) + 1) << 4; // (/16 + 1)*16 + fragment->len = size; // encrypt message with session key m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size); @@ -222,6 +311,63 @@ namespace ssu m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48); m_Session.Send (buf, 48); } + + void SSUData::SendFragmentAck (uint32_t msgID, int fragmentNum) + { + if (fragmentNum > 64) + { + LogPrint ("Fragment number ", fragmentNum, " exceeds 64"); + return; + } + uint8_t buf[64 + 18]; + uint8_t * payload = buf + sizeof (SSUHeader); + *payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag + payload++; + *payload = 1; // number of ACK bitfields + payload++; + // one ack + *(uint32_t *)(payload) = htobe32 (msgID); // msgID + payload += 4; + div_t d = div (fragmentNum, 7); + memset (payload, 0x80, d.quot); // 0x80 means non-last + payload += d.quot; + *payload = 0x40 >> d.rem; // set corresponding bit + payload++; + *payload = 0; // number of fragments + + size_t len = d.quot < 4 ? 48 : 64; // 48 = 37 + 7 + 4 (3+1) + // encrypt message with session key + m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len); + m_Session.Send (buf, len); + } + + void SSUData::ScheduleResend() + { + m_ResendTimer.cancel (); + m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL)); + m_ResendTimer.async_wait (boost::bind (&SSUData::HandleResendTimer, + this, boost::asio::placeholders::error)); + } + + void SSUData::HandleResendTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + for (auto it : m_SentMessages) + { + if (ts >= it.second->nextResendTime && it.second->numResends < MAX_NUM_RESENDS) + { + for (auto f: it.second->fragments) + if (f) m_Session.Send (f->buf, f->len); // resend + + it.second->numResends++; + it.second->nextResendTime += it.second->numResends*RESEND_INTERVAL; + } + } + ScheduleResend (); + } + } } } diff --git a/SSUData.h b/SSUData.h index 4829aa56..45ba31c1 100644 --- a/SSUData.h +++ b/SSUData.h @@ -2,8 +2,11 @@ #define SSU_DATA_H__ #include +#include #include #include +#include +#include #include "I2NPProtocol.h" namespace i2p @@ -11,6 +14,9 @@ namespace i2p namespace ssu { + const size_t SSU_MTU = 1484; + const int RESEND_INTERVAL = 3; // in seconds + const int MAX_NUM_RESENDS = 5; // data flags const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02; const uint8_t DATA_FLAG_WANT_REPLY = 0x04; @@ -19,6 +25,45 @@ namespace ssu const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40; const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80; + struct Fragment + { + int fragmentNum; + size_t len; + bool isLast; + uint8_t buf[SSU_MTU + 18]; + + Fragment () = default; + Fragment (int n, const uint8_t * b, int l, bool last): + fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); }; + }; + + struct FragmentCmp + { + bool operator() (const Fragment * f1, const Fragment * f2) const + { + return f1->fragmentNum < f2->fragmentNum; + }; + }; + + struct IncompleteMessage + { + I2NPMessage * msg; + int nextFragmentNum; + std::set savedFragments; + + IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (0) {}; + ~IncompleteMessage () { for (auto it: savedFragments) { delete it; }; }; + }; + + struct SentMessage + { + std::vector fragments; + uint32_t nextResendTime; // in seconds + int numResends; + + ~SentMessage () { for (auto it: fragments) { delete it; }; }; + }; + class SSUSession; class SSUData { @@ -33,21 +78,20 @@ namespace ssu private: void SendMsgAck (uint32_t msgID); - void ProcessSentMessageAck (uint32_t msgID); + void SendFragmentAck (uint32_t msgID, int fragmentNum); + void ProcessAcks (uint8_t *& buf, uint8_t flag); + void ProcessFragments (uint8_t * buf); + void ProcessSentMessageAck (uint32_t msgID); - private: - - struct IncompleteMessage - { - I2NPMessage * msg; - uint8_t nextFragmentNum; - - IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (1) {}; - }; + void ScheduleResend (); + void HandleResendTimer (const boost::system::error_code& ecode); + + private: SSUSession& m_Session; std::map m_IncomleteMessages; - std::map > m_SentMessages; // msgID -> fragments + std::map m_SentMessages; + boost::asio::deadline_timer m_ResendTimer; }; } } diff --git a/Streaming.cpp b/Streaming.cpp index 7b6ef7c6..01ca8cfc 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -2,6 +2,7 @@ #include #include #include +#include "util.h" #include "Log.h" #include "RouterInfo.h" #include "RouterContext.h" @@ -9,6 +10,7 @@ #include "Timestamp.h" #include "CryptoConst.h" #include "Garlic.h" +#include "NetDb.h" #include "Streaming.h" namespace i2p @@ -17,14 +19,22 @@ namespace stream { Stream::Stream (boost::asio::io_service& service, StreamingDestination * local, const i2p::data::LeaseSet& remote): m_Service (service), m_SendStreamID (0), - m_SequenceNumber (0), m_LastReceivedSequenceNumber (0), m_IsOpen (false), - m_LeaseSetUpdated (true), m_LocalDestination (local), m_RemoteLeaseSet (remote), - m_OutboundTunnel (nullptr), m_ReceiveTimer (m_Service) + m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_IsOpen (false), + m_IsOutgoing(true), m_LeaseSetUpdated (true), m_LocalDestination (local), + m_RemoteLeaseSet (&remote), m_ReceiveTimer (m_Service) { m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); UpdateCurrentRemoteLease (); } + Stream::Stream (boost::asio::io_service& service, StreamingDestination * local): + m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), + m_IsOpen (false), m_IsOutgoing(true), m_LeaseSetUpdated (true), m_LocalDestination (local), + m_RemoteLeaseSet (nullptr), m_ReceiveTimer (m_Service) + { + m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); + } + Stream::~Stream () { m_ReceiveTimer.cancel (); @@ -40,20 +50,29 @@ namespace stream void Stream::HandleNextPacket (Packet * packet) { - if (!m_SendStreamID) - m_SendStreamID = packet->GetReceiveStreamID (); - - uint32_t receivedSeqn = packet->GetSeqn (); + if (!m_SendStreamID) + m_SendStreamID = packet->GetReceiveStreamID (); + + int32_t receivedSeqn = packet->GetSeqn (); + bool isSyn = packet->IsSYN (); + if (!receivedSeqn && !isSyn) + { + // plain ack + LogPrint ("Plain ACK received"); + delete packet; + return; + } + LogPrint ("Received seqn=", receivedSeqn); - if (!receivedSeqn || receivedSeqn == m_LastReceivedSequenceNumber + 1) + if (isSyn || receivedSeqn == m_LastReceivedSequenceNumber + 1) { // 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) + if ((*it)->GetSeqn () == (uint32_t)(m_LastReceivedSequenceNumber + 1)) { Packet * savedPacket = *it; m_SavedPackets.erase (it++); @@ -66,7 +85,14 @@ namespace stream // send ack for last message if (m_IsOpen) - SendQuickAck (); + SendQuickAck (); + else if (isSyn) + { + // we have to send SYN back to incoming connection + m_IsOpen = true; + SendQuickAck (true); + } + } else { @@ -75,9 +101,7 @@ namespace stream // we have received duplicate. Most likely our outbound tunnel is dead LogPrint ("Duplicate message ", receivedSeqn, " received"); UpdateCurrentRemoteLease (); // pick another lease - m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); // pick another tunnel - if (m_OutboundTunnel) - SendQuickAck (); // resend ack for previous message again + SendQuickAck (); // resend ack for previous message again delete packet; // packet dropped } else @@ -106,6 +130,26 @@ namespace stream { LogPrint ("Synchronize"); } + + if (flags & PACKET_FLAG_DELAY_REQUESTED) + { + optionData += 2; + } + + if (flags & PACKET_FLAG_FROM_INCLUDED) + { + optionData += m_RemoteIdentity.FromBuffer (optionData, i2p::data::DEFAULT_IDENTITY_SIZE); + LogPrint ("From identity ", m_RemoteIdentity.Hash ().ToBase64 ()); + if (!m_RemoteLeaseSet) + LogPrint ("Incoming stream from ", m_RemoteIdentity.Hash ().ToBase64 ()); + } + + if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED) + { + uint16_t maxPacketSize = be16toh (*(uint16_t *)optionData); + LogPrint ("Max packet size ", maxPacketSize); + optionData += 2; + } if (flags & PACKET_FLAG_SIGNATURE_INCLUDED) { @@ -113,12 +157,6 @@ namespace stream 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) { @@ -135,6 +173,7 @@ namespace stream LogPrint ("Closed"); SendQuickAck (); // send ack for close explicitly? m_IsOpen = false; + m_ReceiveTimer.cancel (); } } @@ -163,10 +202,10 @@ namespace stream PACKET_FLAG_FROM_INCLUDED | PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED | PACKET_FLAG_NO_ACK); size += 2; // flags - *(uint16_t *)(packet + size) = htobe16 (sizeof (i2p::data::Identity) + 40 + 2); // identity + signature + packet size + *(uint16_t *)(packet + size) = htobe16 (i2p::data::DEFAULT_IDENTITY_SIZE + 40 + 2); // identity + signature + packet size size += 2; // options size - memcpy (packet + size, &m_LocalDestination->GetIdentity (), sizeof (i2p::data::Identity)); - size += sizeof (i2p::data::Identity); // from + memcpy (packet + size, &m_LocalDestination->GetIdentity (), i2p::data::DEFAULT_IDENTITY_SIZE); + size += i2p::data::DEFAULT_IDENTITY_SIZE; // from *(uint16_t *)(packet + size) = htobe16 (STREAMING_MTU); size += 2; // max packet size uint8_t * signature = packet + size; // set it later @@ -193,7 +232,7 @@ namespace stream } - void Stream::SendQuickAck () + void Stream::SendQuickAck (bool syn) { uint8_t packet[MAX_PACKET_SIZE]; size_t size = 0; @@ -208,7 +247,7 @@ namespace stream packet[size] = 0; size++; // NACK count size++; // resend delay - *(uint16_t *)(packet + size) = 0; // nof flags set + *(uint16_t *)(packet + size) = syn ? htobe16 (PACKET_FLAG_SYNCHRONIZE) : 0; // nof flags set size += 2; // flags *(uint16_t *)(packet + size) = 0; // no options size += 2; // options size @@ -222,7 +261,8 @@ namespace stream if (m_IsOpen) { m_IsOpen = false; - uint8_t packet[MAX_PACKET_SIZE]; + Packet * p = new Packet (); + uint8_t * packet = p->GetBuffer (); size_t size = 0; *(uint32_t *)(packet + size) = htobe32 (m_SendStreamID); size += 4; // sendStreamID @@ -235,7 +275,7 @@ namespace stream packet[size] = 0; size++; // NACK count size++; // resend delay - *(uint16_t *)(packet + size) = PACKET_FLAG_CLOSE | PACKET_FLAG_SIGNATURE_INCLUDED; + *(uint16_t *)(packet + size) = htobe16 (PACKET_FLAG_CLOSE | PACKET_FLAG_SIGNATURE_INCLUDED); size += 2; // flags *(uint16_t *)(packet + size) = htobe16 (40); // 40 bytes signature size += 2; // options size @@ -244,8 +284,9 @@ namespace stream size += 40; // signature m_LocalDestination->Sign (packet, size, signature); - if (SendPacket (packet, size)) - LogPrint ("FIN sent"); + p->len = size; + m_Service.post (boost::bind (&Stream::SendPacket, this, p)); + LogPrint ("FIN sent"); } } @@ -281,27 +322,36 @@ namespace stream } bool Stream::SendPacket (const uint8_t * buf, size_t len) - { - const I2NPMessage * leaseSet = nullptr; + { + if (!m_RemoteLeaseSet) + { + UpdateCurrentRemoteLease (); + if (!m_RemoteLeaseSet) + { + LogPrint ("Can't send packet. Missing remote LeaseSet"); + return false; + } + } + + I2NPMessage * leaseSet = nullptr; if (m_LeaseSetUpdated) { - leaseSet = m_LocalDestination->GetLeaseSet (); + leaseSet = m_LocalDestination->GetLeaseSetMsg (); m_LeaseSetUpdated = false; } - I2NPMessage * msg = i2p::garlic::routing.WrapMessage (m_RemoteLeaseSet, + I2NPMessage * msg = i2p::garlic::routing.WrapMessage (*m_RemoteLeaseSet, CreateDataMessage (this, buf, len), leaseSet); - if (!m_OutboundTunnel || m_OutboundTunnel->IsFailed ()) - m_OutboundTunnel = m_LocalDestination->GetTunnelPool ()->GetNextOutboundTunnel (); - if (m_OutboundTunnel) + auto outboundTunnel = m_LocalDestination->GetTunnelPool ()->GetNextOutboundTunnel (); + if (outboundTunnel) { auto ts = i2p::util::GetMillisecondsSinceEpoch (); if (ts >= m_CurrentRemoteLease.endDate) UpdateCurrentRemoteLease (); if (ts < m_CurrentRemoteLease.endDate) { - m_OutboundTunnel->SendTunnelDataMsg (m_CurrentRemoteLease.tunnelGateway, m_CurrentRemoteLease.tunnelID, msg); + outboundTunnel->SendTunnelDataMsg (m_CurrentRemoteLease.tunnelGateway, m_CurrentRemoteLease.tunnelID, msg); return true; } else @@ -320,18 +370,30 @@ namespace stream void Stream::UpdateCurrentRemoteLease () { - auto leases = m_RemoteLeaseSet.GetNonExpiredLeases (); - if (!leases.empty ()) - { - uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1); - m_CurrentRemoteLease = leases[i]; - } + if (!m_RemoteLeaseSet) + { + m_RemoteLeaseSet = i2p::data::netdb.FindLeaseSet (m_RemoteIdentity.Hash ()); + if (!m_RemoteLeaseSet) + LogPrint ("LeaseSet ", m_RemoteIdentity.Hash ().ToBase64 (), " not found"); + } + if (m_RemoteLeaseSet) + { + auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); + if (!leases.empty ()) + { + uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1); + m_CurrentRemoteLease = leases[i]; + } + else + m_CurrentRemoteLease.endDate = 0; + } else m_CurrentRemoteLease.endDate = 0; } - StreamingDestination::StreamingDestination (): m_LeaseSet (nullptr) + StreamingDestination::StreamingDestination (boost::asio::io_service& service): + m_Service (service), m_LeaseSet (nullptr) { m_Keys = i2p::data::CreateRandomKeys (); @@ -343,7 +405,8 @@ namespace stream m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel } - StreamingDestination::StreamingDestination (const std::string& fullPath): m_LeaseSet (nullptr) + StreamingDestination::StreamingDestination (boost::asio::io_service& service, const std::string& fullPath): + m_Service (service), m_LeaseSet (nullptr) { std::ifstream s(fullPath.c_str (), std::ifstream::binary); if (s.is_open ()) @@ -356,38 +419,53 @@ namespace stream CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey); - m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel + m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel } StreamingDestination::~StreamingDestination () { - if (m_LeaseSet) - DeleteI2NPMessage (m_LeaseSet); if (m_Pool) i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool); + delete m_LeaseSet; } void StreamingDestination::HandleNextPacket (Packet * packet) { uint32_t sendStreamID = packet->GetSendStreamID (); - auto it = m_Streams.find (sendStreamID); - if (it != m_Streams.end ()) - it->second->HandleNextPacket (packet); - else + if (sendStreamID) { - LogPrint ("Unknown stream ", sendStreamID); - delete packet; + auto it = m_Streams.find (sendStreamID); + if (it != m_Streams.end ()) + it->second->HandleNextPacket (packet); + else + { + LogPrint ("Unknown stream ", sendStreamID); + delete packet; + } + } + else // new incoming stream + { + auto incomingStream = CreateNewIncomingStream (); + incomingStream->HandleNextPacket (packet); + if (m_Acceptor != nullptr) + m_Acceptor (incomingStream); } } - Stream * StreamingDestination::CreateNewStream (boost::asio::io_service& service, - const i2p::data::LeaseSet& remote) + Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote) { - Stream * s = new Stream (service, this, remote); + Stream * s = new Stream (m_Service, this, remote); m_Streams[s->GetRecvStreamID ()] = s; return s; } + Stream * StreamingDestination::CreateNewIncomingStream () + { + Stream * s = new Stream (m_Service, this); + m_Streams[s->GetRecvStreamID ()] = s; + return s; + } + void StreamingDestination::DeleteStream (Stream * stream) { if (stream) @@ -396,68 +474,29 @@ namespace stream delete stream; } } - - void StreamingDestination::UpdateLeaseSet () - { - auto newLeaseSet = CreateLeaseSet (); - // TODO: make it atomic - auto oldLeaseSet = m_LeaseSet; - m_LeaseSet = newLeaseSet; - if (oldLeaseSet) - DeleteI2NPMessage (oldLeaseSet); - for (auto it: m_Streams) - it.second->SetLeaseSetUpdated (); - } - const I2NPMessage * StreamingDestination::GetLeaseSet () + I2NPMessage * StreamingDestination::GetLeaseSetMsg () + { + return CreateDatabaseStoreMsg (GetLeaseSet ()); + } + + const i2p::data::LeaseSet * StreamingDestination::GetLeaseSet () { - if (!m_LeaseSet) - m_LeaseSet = CreateLeaseSet (); - else - RenewI2NPMessageHeader (m_LeaseSet); + if (!m_Pool) return nullptr; + if (!m_LeaseSet || m_LeaseSet->HasExpiredLeases ()) + { + auto newLeaseSet = new i2p::data::LeaseSet (*m_Pool); + // TODO: make it atomic + auto oldLeaseSet = m_LeaseSet; + m_LeaseSet = newLeaseSet; + delete oldLeaseSet; + for (auto it: m_Streams) + it.second->SetLeaseSetUpdated (); + } return m_LeaseSet; } - I2NPMessage * StreamingDestination::CreateLeaseSet () const - { - I2NPMessage * m = NewI2NPMessage (); - I2NPDatabaseStoreMsg * msg = (I2NPDatabaseStoreMsg *)m->GetPayload (); - memcpy (msg->key, (const uint8_t *)m_IdentHash, 32); - msg->type = 1; // LeaseSet - msg->replyToken = 0; - - uint8_t * buf = m->GetPayload () + sizeof (I2NPDatabaseStoreMsg); - size_t size = 0; - memcpy (buf + size, &m_Keys.pub, sizeof (m_Keys.pub)); - size += sizeof (m_Keys.pub); // destination - memcpy (buf + size, m_Pool->GetEncryptionPublicKey (), 256); - size += 256; // encryption key - memset (buf + size, 0, 128); - size += 128; // signing key - auto tunnels = m_Pool->GetInboundTunnels (5); // 5 tunnels maximum - buf[size] = tunnels.size (); // num leases - size++; // num - for (auto it: tunnels) - { - auto tunnel = it; - memcpy (buf + size, (const uint8_t *)tunnel->GetNextIdentHash (), 32); - size += 32; // tunnel_gw - *(uint32_t *)(buf + size) = htobe32 (tunnel->GetNextTunnelID ()); - size += 4; // tunnel_id - uint64_t ts = tunnel->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - 60; // 1 minute before expiration - ts *= 1000; // in milliseconds - *(uint64_t *)(buf + size) = htobe64 (ts); - size += 8; // end_date - } - Sign (buf, size, buf+ size); - size += 40; // signature - LogPrint ("Local LeaseSet of ", tunnels.size (), " leases created"); - m->len += size + sizeof (I2NPDatabaseStoreMsg); - FillI2NPMessageHeader (m, eI2NPDatabaseStore); - return m; - } - - void StreamingDestination::Sign (uint8_t * buf, int len, uint8_t * signature) const + void StreamingDestination::Sign (const uint8_t * buf, int len, uint8_t * signature) const { CryptoPP::DSA::Signer signer (m_SigningPrivateKey); signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, len, signature); @@ -467,7 +506,11 @@ namespace stream void StreamingDestinations::Start () { if (!m_SharedLocalDestination) - m_SharedLocalDestination = new StreamingDestination (); + { + m_SharedLocalDestination = new StreamingDestination (m_Service); + m_Destinations[m_SharedLocalDestination->GetIdentHash ()] = m_SharedLocalDestination; + } + LoadLocalDestinations (); m_IsRunning = true; m_Thread = new std::thread (std::bind (&StreamingDestinations::Run, this)); @@ -475,7 +518,10 @@ namespace stream void StreamingDestinations::Stop () { - delete m_SharedLocalDestination; + for (auto it: m_Destinations) + delete it.second; + m_Destinations.clear (); + m_SharedLocalDestination = 0; // deleted through m_Destination m_IsRunning = false; m_Service.stop (); @@ -492,20 +538,49 @@ namespace stream m_Service.run (); } + void StreamingDestinations::LoadLocalDestinations () + { + int numDestinations = 0; + boost::filesystem::path p (i2p::util::filesystem::GetDataDir()); + boost::filesystem::directory_iterator end; + for (boost::filesystem::directory_iterator it (p); it != end; ++it) + { + if (boost::filesystem::is_regular_file (*it) && it->path ().extension () == ".dat") + { + auto fullPath = +#if BOOST_VERSION > 10500 + it->path().string(); +#else + it->path(); +#endif + auto localDestination = new StreamingDestination (m_Service, fullPath); + m_Destinations[localDestination->GetIdentHash ()] = localDestination; + numDestinations++; + } + } + if (numDestinations > 0) + LogPrint (numDestinations, " local destinations loaded"); + } + Stream * StreamingDestinations::CreateClientStream (const i2p::data::LeaseSet& remote) { if (!m_SharedLocalDestination) return nullptr; - return m_SharedLocalDestination->CreateNewStream (m_Service, remote); + return m_SharedLocalDestination->CreateNewOutgoingStream (remote); } - - void StreamingDestinations::DeleteClientStream (Stream * stream) - { - if (m_SharedLocalDestination) - m_SharedLocalDestination->DeleteStream (stream); - else - delete stream; - } + void StreamingDestinations::DeleteStream (Stream * stream) + { + if (stream) + { + m_Service.post ( + [=](void) + { + stream->GetLocalDestination ()->DeleteStream (stream); + } + ); + } + } + void StreamingDestinations::HandleNextPacket (i2p::data::IdentHash destination, Packet * packet) { m_Service.post (boost::bind (&StreamingDestinations::PostNextPacket, this, destination, packet)); @@ -513,9 +588,14 @@ namespace stream void StreamingDestinations::PostNextPacket (i2p::data::IdentHash destination, Packet * packet) { - // TODO: we have onle one destination, might be more - if (m_SharedLocalDestination) - m_SharedLocalDestination->HandleNextPacket (packet); + auto it = m_Destinations.find (destination); + if (it != m_Destinations.end ()) + it->second->HandleNextPacket (packet); + else + { + LogPrint ("Local destination ", destination.ToBase64 (), " not found"); + delete packet; + } } Stream * CreateStream (const i2p::data::LeaseSet& remote) @@ -525,7 +605,7 @@ namespace stream void DeleteStream (Stream * stream) { - destinations.DeleteClientStream (stream); + destinations.DeleteStream (stream); } void StartStreaming () @@ -537,6 +617,11 @@ namespace stream { destinations.Stop (); } + + StreamingDestination * GetSharedLocalDestination () + { + return destinations.GetSharedLocalDestination (); + } void HandleDataMessage (i2p::data::IdentHash destination, const uint8_t * buf, size_t len) { @@ -554,7 +639,7 @@ namespace stream uncompressed->len = decompressor.MaxRetrievable (); if (uncompressed->len > MAX_PACKET_SIZE) { - LogPrint ("Recieved packet size exceeds mac packet size"); + LogPrint ("Received packet size ", uncompressed->len, " exceeds max packet size"); uncompressed->len = MAX_PACKET_SIZE; } decompressor.Get (uncompressed->buf, uncompressed->len); diff --git a/Streaming.h b/Streaming.h index 5a0ed383..33c8dfeb 100644 --- a/Streaming.h +++ b/Streaming.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -14,7 +15,6 @@ #include "Identity.h" #include "LeaseSet.h" #include "I2NPProtocol.h" -#include "Tunnel.h" #include "TunnelPool.h" namespace i2p @@ -34,7 +34,7 @@ namespace stream const uint16_t PACKET_FLAG_NO_ACK = 0x0400; const size_t STREAMING_MTU = 1730; - const size_t MAX_PACKET_SIZE = 1754; + const size_t MAX_PACKET_SIZE = 4096; struct Packet { @@ -55,6 +55,8 @@ namespace stream uint16_t GetOptionSize () const { return be16toh (*(uint16_t *)GetOption ()); }; const uint8_t * GetOptionData () const { return GetOption () + 2; }; const uint8_t * GetPayload () const { return GetOptionData () + GetOptionSize (); }; + + bool IsSYN () const { return GetFlags () & PACKET_FLAG_SYNCHRONIZE; }; }; struct PacketCmp @@ -70,13 +72,16 @@ namespace stream { public: - Stream (boost::asio::io_service& service, StreamingDestination * local, const i2p::data::LeaseSet& remote); + Stream (boost::asio::io_service& service, StreamingDestination * local, const i2p::data::LeaseSet& remote); // outgoing + Stream (boost::asio::io_service& service, StreamingDestination * local); // incoming + ~Stream (); uint32_t GetSendStreamID () const { return m_SendStreamID; }; uint32_t GetRecvStreamID () const { return m_RecvStreamID; }; - const i2p::data::LeaseSet& GetRemoteLeaseSet () const { return m_RemoteLeaseSet; }; + const i2p::data::LeaseSet * GetRemoteLeaseSet () const { return m_RemoteLeaseSet; }; bool IsOpen () const { return m_IsOpen; }; bool IsEstablished () const { return m_SendStreamID; }; + StreamingDestination * GetLocalDestination () { return m_LocalDestination; }; void HandleNextPacket (Packet * packet); size_t Send (const uint8_t * buf, size_t len, int timeout); // timeout in seconds @@ -90,7 +95,7 @@ namespace stream private: - void SendQuickAck (); + void SendQuickAck (bool syn = false); bool SendPacket (Packet * packet); bool SendPacket (const uint8_t * buf, size_t len); @@ -106,14 +111,15 @@ namespace stream private: boost::asio::io_service& m_Service; - uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber, m_LastReceivedSequenceNumber; - bool m_IsOpen, m_LeaseSetUpdated; + uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber; + int32_t m_LastReceivedSequenceNumber; + bool m_IsOpen, m_IsOutgoing, m_LeaseSetUpdated; StreamingDestination * m_LocalDestination; - const i2p::data::LeaseSet& m_RemoteLeaseSet; + i2p::data::Identity m_RemoteIdentity; + const i2p::data::LeaseSet * m_RemoteLeaseSet; i2p::data::Lease m_CurrentRemoteLease; std::queue m_ReceiveQueue; std::set m_SavedPackets; - i2p::tunnel::OutboundTunnel * m_OutboundTunnel; boost::asio::deadline_timer m_ReceiveTimer; }; @@ -121,41 +127,44 @@ namespace stream { public: - StreamingDestination (); - StreamingDestination (const std::string& fullPath); + StreamingDestination (boost::asio::io_service& service); + StreamingDestination (boost::asio::io_service& service, const std::string& fullPath); ~StreamingDestination (); const i2p::data::PrivateKeys& GetKeys () const { return m_Keys; }; - const i2p::data::Identity& GetIdentity () const { return m_Keys.pub; }; - const I2NPMessage * GetLeaseSet (); - i2p::tunnel::TunnelPool * GetTunnelPool () const { return m_Pool; }; - void Sign (uint8_t * buf, int len, uint8_t * signature) const; + I2NPMessage * GetLeaseSetMsg (); + const i2p::data::LeaseSet * GetLeaseSet (); + i2p::tunnel::TunnelPool * GetTunnelPool () const { return m_Pool; }; - Stream * CreateNewStream (boost::asio::io_service& service, const i2p::data::LeaseSet& remote); - void DeleteStream (Stream * stream); + Stream * CreateNewOutgoingStream (const i2p::data::LeaseSet& remote); + void DeleteStream (Stream * stream); + void SetAcceptor (const std::function& acceptor) { m_Acceptor = acceptor; }; void HandleNextPacket (Packet * packet); // implements LocalDestination - void UpdateLeaseSet (); const i2p::data::IdentHash& GetIdentHash () const { return m_IdentHash; }; + const i2p::data::Identity& GetIdentity () const { return m_Keys.pub; }; const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; }; - - private: - - I2NPMessage * CreateLeaseSet () const; - + void Sign (const uint8_t * buf, int len, uint8_t * signature) const; + + private: + + Stream * CreateNewIncomingStream (); + private: + boost::asio::io_service& m_Service; std::map m_Streams; i2p::data::PrivateKeys m_Keys; i2p::data::IdentHash m_IdentHash; uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; i2p::tunnel::TunnelPool * m_Pool; - I2NPMessage * m_LeaseSet; + i2p::data::LeaseSet * m_LeaseSet; CryptoPP::DSA::PrivateKey m_SigningPrivateKey; + std::function m_Acceptor; }; class StreamingDestinations @@ -172,11 +181,13 @@ namespace stream void HandleNextPacket (i2p::data::IdentHash destination, Packet * packet); Stream * CreateClientStream (const i2p::data::LeaseSet& remote); - void DeleteClientStream (Stream * stream); + void DeleteStream (Stream * stream); + StreamingDestination * GetSharedLocalDestination () const { return m_SharedLocalDestination; }; private: void Run (); + void LoadLocalDestinations (); void PostNextPacket (i2p::data::IdentHash destination, Packet * packet); private: @@ -186,6 +197,7 @@ namespace stream boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; + std::map m_Destinations; StreamingDestination * m_SharedLocalDestination; }; @@ -193,6 +205,7 @@ namespace stream void DeleteStream (Stream * stream); void StartStreaming (); void StopStreaming (); + StreamingDestination * GetSharedLocalDestination (); // assuming data is I2CP message void HandleDataMessage (i2p::data::IdentHash destination, const uint8_t * buf, size_t len); @@ -213,6 +226,11 @@ namespace stream return; } } + if (!m_IsOpen) + { + handler (boost::asio::error::make_error_code (boost::asio::error::connection_reset), 0); + return; + } m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout)); m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode) { this->HandleReceiveTimer (ecode, buffer, handler); }); diff --git a/TransitTunnel.cpp b/TransitTunnel.cpp index 65b0be4f..9ed8a542 100644 --- a/TransitTunnel.cpp +++ b/TransitTunnel.cpp @@ -30,11 +30,11 @@ namespace tunnel EncryptTunnelMsg (tunnelMsg); LogPrint ("TransitTunnel: ",m_TunnelID,"->", m_NextTunnelID); + m_NumTransmittedBytes += tunnelMsg->GetLength (); *(uint32_t *)(tunnelMsg->GetPayload ()) = htobe32 (m_NextTunnelID); FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData); - + i2p::transports.SendMessage (m_NextIdent, tunnelMsg); - m_NumTransmittedBytes += tunnelMsg->GetLength (); } void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg) @@ -48,6 +48,7 @@ namespace tunnel TunnelMessageBlock block; block.deliveryType = eDeliveryTypeLocal; block.data = msg; + std::unique_lock l(m_SendMutex); m_Gateway.SendTunnelDataMsg (block); } @@ -81,4 +82,4 @@ namespace tunnel } } } -} \ No newline at end of file +} diff --git a/TransitTunnel.h b/TransitTunnel.h index ebd7ffd5..e71c16e1 100644 --- a/TransitTunnel.h +++ b/TransitTunnel.h @@ -2,6 +2,7 @@ #define TRANSIT_TUNNEL_H__ #include +#include #include "aes.h" #include "I2NPProtocol.h" #include "TunnelEndpoint.h" @@ -55,6 +56,7 @@ namespace tunnel private: + std::mutex m_SendMutex; TunnelGateway m_Gateway; }; @@ -65,7 +67,8 @@ namespace tunnel TransitTunnelEndpoint (uint32_t receiveTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * layerKey,const uint8_t * ivKey): - TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey) {}; + TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey), + m_Endpoint (false) {}; // transit endpoint is always outbound void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); } diff --git a/Transports.cpp b/Transports.cpp index 249e5f0e..851e244d 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -52,6 +52,7 @@ namespace i2p { i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair (); i2p::data::CreateRandomDHKeysPair (pair); + std::unique_lock l(m_AcquiredMutex); m_Queue.push (pair); } } @@ -61,6 +62,7 @@ namespace i2p { if (!m_Queue.empty ()) { + std::unique_lock l(m_AcquiredMutex); auto pair = m_Queue.front (); m_Queue.pop (); m_Acquired.notify_one (); @@ -230,9 +232,9 @@ namespace i2p else { // existing session not found. create new - // try NTCP first + // try NTCP first if message size < 16K auto address = r->GetNTCPAddress (); - if (address && !r->UsesIntroducer () && !r->IsUnreachable ()) + if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < i2p::ntcp::NTCP_MAX_MESSAGE_SIZE) { auto s = new i2p::ntcp::NTCPClient (m_Service, address->host, address->port, *r); AddNTCPSession (s); @@ -245,7 +247,10 @@ namespace i2p if (s) s->SendI2NPMessage (msg); else + { LogPrint ("No NTCP and SSU addresses available"); + DeleteI2NPMessage (msg); + } } } } @@ -253,10 +258,28 @@ namespace i2p { LogPrint ("Router not found. Requested"); i2p::data::netdb.RequestDestination (ident); + DeleteI2NPMessage (msg); // TODO: implement a placeholder for router and send once it's available } } } + void Transports::CloseSession (const i2p::data::RouterInfo * router) + { + if (!router) return; + m_Service.post (boost::bind (&Transports::PostCloseSession, this, router)); + } + + void Transports::PostCloseSession (const i2p::data::RouterInfo * router) + { + auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr; + if (ssuSession) // try SSU first + { + m_SSUServer->DeleteSession (ssuSession); + LogPrint ("SSU session closed"); + } + // TODO: delete NTCP + } + void Transports::DetectExternalIP () { for (int i = 0; i < 5; i ++) diff --git a/Transports.h b/Transports.h index b0ff8455..e5e6ddfa 100644 --- a/Transports.h +++ b/Transports.h @@ -63,13 +63,15 @@ namespace i2p i2p::ntcp::NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident); void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); - + void CloseSession (const i2p::data::RouterInfo * router); + private: 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 PostCloseSession (const i2p::data::RouterInfo * router); + void DetectExternalIP (); private: diff --git a/Tunnel.cpp b/Tunnel.cpp index 0c1fe454..94fc9b81 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -14,8 +14,8 @@ namespace i2p namespace tunnel { - Tunnel::Tunnel (TunnelConfig * config): m_Config (config), m_Pool (nullptr), - m_IsEstablished (false), m_IsFailed (false) + Tunnel::Tunnel (TunnelConfig * config): + m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending) { } @@ -111,7 +111,7 @@ namespace tunnel hop = hop->prev; } - m_IsEstablished = true; + bool established = true; hop = m_Config->GetFirstHop (); while (hop) { @@ -119,10 +119,10 @@ namespace tunnel LogPrint ("Ret code=", (int)record->ret); if (record->ret) // if any of participants declined the tunnel is not established - m_IsEstablished = false; + established = false; hop = hop->next; } - if (m_IsEstablished) + if (established) { // change reply keys to layer keys hop = m_Config->GetFirstHop (); @@ -132,7 +132,8 @@ namespace tunnel hop = hop->next; } } - return m_IsEstablished; + if (established) m_State = eTunnelStateEstablished; + return established; } void Tunnel::EncryptTunnelMsg (I2NPMessage * tunnelMsg) @@ -148,7 +149,7 @@ namespace tunnel void InboundTunnel::HandleTunnelDataMsg (I2NPMessage * msg) { - if (IsFailed ()) SetFailed (false); // incoming messages means a tunnel is alive + if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive msg->from = this; EncryptTunnelMsg (msg); m_Endpoint.HandleDecryptedTunnelDataMsg (msg); @@ -361,10 +362,12 @@ namespace tunnel void Tunnels::ManageTunnels () { // check pending tunnel. if something is still there, wipe it out - // because it wouldn't be reponded anyway + // because it wouldn't be responded anyway for (auto& it : m_PendingTunnels) { LogPrint ("Pending tunnel build request ", it.first, " has not been responded. Deleted"); + if (it.second->GetTunnelConfig ()->GetFirstHop ()->isGateway) // outbound + i2p::transports.CloseSession (it.second->GetTunnelConfig ()->GetFirstHop ()->router); delete it.second; } m_PendingTunnels.clear (); @@ -398,6 +401,7 @@ namespace tunnel auto pool = (*it)->GetTunnelPool (); if (pool) pool->TunnelExpired (*it); + delete *it; it = m_OutboundTunnels.erase (it); } else @@ -430,6 +434,7 @@ namespace tunnel auto pool = it->second->GetTunnelPool (); if (pool) pool->TunnelExpired (it->second); + delete it->second; it = m_InboundTunnels.erase (it); } else @@ -465,7 +470,9 @@ namespace tunnel if (ts > it->second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) { LogPrint ("Transit tunnel ", it->second->GetTunnelID (), " expired"); + auto tmp = it->second; it = m_TransitTunnels.erase (it); + delete tmp; } else it++; diff --git a/Tunnel.h b/Tunnel.h index 8ae3e392..8feb4926 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -22,6 +22,14 @@ namespace i2p namespace tunnel { const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes + + enum TunnelState + { + eTunnelStatePending, + eTunnelStateEstablished, + eTunnelStateTestFailed, + eTunnelStateFailed + }; class OutboundTunnel; class InboundTunnel; @@ -35,9 +43,10 @@ namespace tunnel void Build (uint32_t replyMsgID, OutboundTunnel * outboundTunnel = 0); TunnelConfig * GetTunnelConfig () const { return m_Config; } - bool IsEstablished () const { return m_IsEstablished; }; - bool IsFailed () const { return m_IsFailed; }; - void SetFailed (bool failed) { m_IsFailed = failed; } + TunnelState GetState () const { return m_State; }; + void SetState (TunnelState state) { m_State = state; }; + bool IsEstablished () const { return m_State == eTunnelStateEstablished; }; + bool IsFailed () const { return m_State == eTunnelStateFailed; }; TunnelPool * GetTunnelPool () const { return m_Pool; }; void SetTunnelPool (TunnelPool * pool) { m_Pool = pool; }; @@ -53,7 +62,7 @@ namespace tunnel TunnelConfig * m_Config; TunnelPool * m_Pool; // pool, tunnel belongs to, or null - bool m_IsEstablished, m_IsFailed; + TunnelState m_State; }; class OutboundTunnel: public Tunnel @@ -81,7 +90,7 @@ namespace tunnel { public: - InboundTunnel (TunnelConfig * config): Tunnel (config) {}; + InboundTunnel (TunnelConfig * config): Tunnel (config), m_Endpoint (true) {}; void HandleTunnelDataMsg (I2NPMessage * msg); size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; diff --git a/TunnelEndpoint.cpp b/TunnelEndpoint.cpp index cfbc39ec..254c56ab 100644 --- a/TunnelEndpoint.cpp +++ b/TunnelEndpoint.cpp @@ -1,14 +1,22 @@ #include "I2PEndian.h" #include #include "Log.h" +#include "NetDb.h" #include "I2NPProtocol.h" #include "Transports.h" +#include "RouterContext.h" #include "TunnelEndpoint.h" namespace i2p { namespace tunnel { + TunnelEndpoint::~TunnelEndpoint () + { + for (auto it: m_IncompleteMessages) + i2p::DeleteI2NPMessage (it.second.data); + } + void TunnelEndpoint::HandleDecryptedTunnelDataMsg (I2NPMessage * msg) { m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE; @@ -19,6 +27,17 @@ namespace tunnel { LogPrint ("TunnelMessage: zero found at ", (int)(zero-decrypted)); uint8_t * fragment = zero + 1; + // verify checksum + memcpy (msg->GetPayload () + TUNNEL_DATA_MSG_SIZE, msg->GetPayload () + 4, 16); // copy iv to the end + uint8_t hash[32]; + CryptoPP::SHA256().CalculateDigest (hash, fragment, TUNNEL_DATA_MSG_SIZE -(fragment - msg->GetPayload ()) + 16); // payload + iv + if (memcmp (hash, decrypted, 4)) + { + LogPrint ("TunnelMessage: checksum verification failed"); + i2p::DeleteI2NPMessage (msg); + return; + } + // process fragments while (fragment < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE) { uint8_t flag = fragment[0]; @@ -80,7 +99,6 @@ namespace tunnel msg->offset = fragment - msg->buf; msg->len = msg->offset + size; - bool isLastMessage = false; if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE) { // this is not last message. we have to copy it @@ -90,10 +108,7 @@ namespace tunnel *(m.data) = *msg; } else - { m.data = msg; - isLastMessage = true; - } if (!isFollowOnFragment && isLastFragment) HandleNextMessage (m); @@ -108,36 +123,8 @@ namespace tunnel } else { - auto it = m_IncompleteMessages.find (msgID); - if (it != m_IncompleteMessages.end()) - { - if (fragmentNum == it->second.nextFragmentNum) - { - I2NPMessage * incompleteMessage = it->second.data; - memcpy (incompleteMessage->buf + incompleteMessage->len, fragment, size); // concatenate fragment - incompleteMessage->len += size; - if (isLastFragment) - { - // message complete - HandleNextMessage (it->second); - m_IncompleteMessages.erase (it); - } - else - it->second.nextFragmentNum++; - } - else - { - LogPrint ("Unexpected fragment ", fragmentNum, " instead ", it->second.nextFragmentNum, " of message ", msgID, ". Discarded"); - m_IncompleteMessages.erase (it); // TODO: store unexpect fragment for a while - } - } - else - LogPrint ("First fragment of message ", msgID, " not found. Discarded"); - - if (isLastMessage) - // last message is follow-on fragment - // not passed to anywhere because first fragment - i2p::DeleteI2NPMessage (msg); + m.nextFragmentNum = fragmentNum; + HandleFollowOnFragment (msgID, isLastFragment, m); } } else @@ -154,6 +141,49 @@ namespace tunnel } } + void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m) + { + auto fragment = m.data->GetBuffer (); + auto size = m.data->GetLength (); + auto it = m_IncompleteMessages.find (msgID); + if (it != m_IncompleteMessages.end()) + { + if (m.nextFragmentNum == it->second.nextFragmentNum) + { + I2NPMessage * incompleteMessage = it->second.data; + if (incompleteMessage->len + size < I2NP_MAX_MESSAGE_SIZE) // check if messega is not too long + { + memcpy (incompleteMessage->buf + incompleteMessage->len, fragment, size); // concatenate fragment + incompleteMessage->len += size; + if (isLastFragment) + { + // message complete + HandleNextMessage (it->second); + m_IncompleteMessages.erase (it); + } + else + it->second.nextFragmentNum++; + } + else + { + LogPrint ("Fragment ", m.nextFragmentNum, " of message ", msgID, "exceeds max I2NP message size. Message dropped"); + i2p::DeleteI2NPMessage (it->second.data); + m_IncompleteMessages.erase (it); + } + } + else + { + LogPrint ("Unexpected fragment ", m.nextFragmentNum, " instead ", it->second.nextFragmentNum, " of message ", msgID, ". Discarded"); + i2p::DeleteI2NPMessage (it->second.data); + m_IncompleteMessages.erase (it); // TODO: store unexpected fragment for a while + } + } + else + LogPrint ("First fragment of message ", msgID, " not found. Discarded"); + + i2p::DeleteI2NPMessage (m.data); + } + void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg) { LogPrint ("TunnelMessage: handle fragment of ", msg.data->GetLength ()," bytes. Msg type ", (int)msg.data->GetHeader()->typeID); @@ -166,7 +196,28 @@ namespace tunnel i2p::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data)); break; case eDeliveryTypeRouter: - i2p::transports.SendMessage (msg.hash, msg.data); + if (msg.hash == i2p::context.GetRouterInfo ().GetIdentHash ()) // check if message is sent to us + i2p::HandleI2NPMessage (msg.data); + else + { + // to somebody else + if (!m_IsInbound) // outbound transit tunnel + { + if (msg.data->GetHeader()->typeID == eI2NPDatabaseStore) + { + // catch RI + auto ds = NewI2NPMessage (); + *ds = *(msg.data); + i2p::data::netdb.PostI2NPMsg (ds); + } + i2p::transports.SendMessage (msg.hash, msg.data); + } + else // we shouldn't send this message. possible leakage + { + LogPrint ("Message to another router arrived from an inbound tunnel. Dropped"); + i2p::DeleteI2NPMessage (msg.data); + } + } break; default: LogPrint ("TunnelMessage: Unknown delivery type ", (int)msg.deliveryType); diff --git a/TunnelEndpoint.h b/TunnelEndpoint.h index 2323e574..d9fa4bb6 100644 --- a/TunnelEndpoint.h +++ b/TunnelEndpoint.h @@ -13,25 +13,28 @@ namespace tunnel { class TunnelEndpoint { + struct TunnelMessageBlockEx: public TunnelMessageBlock + { + uint8_t nextFragmentNum; + }; + public: - TunnelEndpoint (): m_NumReceivedBytes (0) {}; + TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0) {}; + ~TunnelEndpoint (); size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; void HandleDecryptedTunnelDataMsg (I2NPMessage * msg); private: + void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m); void HandleNextMessage (const TunnelMessageBlock& msg); - private: - - struct TunnelMessageBlockEx: public TunnelMessageBlock - { - uint8_t nextFragmentNum; - }; + private: std::map m_IncompleteMessages; + bool m_IsInbound; size_t m_NumReceivedBytes; }; } diff --git a/TunnelGateway.cpp b/TunnelGateway.cpp index c85e92e6..4a004edc 100644 --- a/TunnelGateway.cpp +++ b/TunnelGateway.cpp @@ -107,13 +107,10 @@ namespace tunnel } } - const std::vector TunnelGatewayBuffer::GetTunnelDataMsgs () + void TunnelGatewayBuffer::ClearTunnelDataMsgs () { - CompleteCurrentTunnelDataMessage (); - std::vector ret = m_TunnelDataMsgs; // TODO: implement it better - m_TunnelDataMsgs.clear (); - return ret; - } + m_TunnelDataMsgs.clear (); + } void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage () { @@ -162,6 +159,7 @@ namespace tunnel void TunnelGateway::SendBuffer () { + m_Buffer.CompleteCurrentTunnelDataMessage (); auto tunnelMsgs = m_Buffer.GetTunnelDataMsgs (); for (auto tunnelMsg : tunnelMsgs) { @@ -170,6 +168,7 @@ namespace tunnel i2p::transports.SendMessage (m_Tunnel->GetNextIdentHash (), tunnelMsg); m_NumSentBytes += TUNNEL_DATA_MSG_SIZE; } + m_Buffer.ClearTunnelDataMsgs (); } } } diff --git a/TunnelGateway.h b/TunnelGateway.h index aec0ca03..abed9288 100644 --- a/TunnelGateway.h +++ b/TunnelGateway.h @@ -16,12 +16,13 @@ namespace tunnel TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {}; void PutI2NPMsg (const TunnelMessageBlock& block); - const std::vector GetTunnelDataMsgs (); + const std::vector& GetTunnelDataMsgs () const { return m_TunnelDataMsgs; }; + void ClearTunnelDataMsgs (); + void CompleteCurrentTunnelDataMessage (); private: void CreateCurrentTunnelDataMessage (); - void CompleteCurrentTunnelDataMessage (); private: @@ -37,11 +38,11 @@ namespace tunnel TunnelGateway (TunnelBase * tunnel): m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {}; - void SendTunnelDataMsg (const TunnelMessageBlock& block); - void PutTunnelDataMsg (const TunnelMessageBlock& block); - void SendBuffer (); + void SendTunnelDataMsg (const TunnelMessageBlock& block); + void PutTunnelDataMsg (const TunnelMessageBlock& block); + void SendBuffer (); size_t GetNumSentBytes () const { return m_NumSentBytes; }; - + private: TunnelBase * m_Tunnel; diff --git a/TunnelPool.cpp b/TunnelPool.cpp index 1b6fa8cb..e370cfe7 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -11,7 +11,7 @@ namespace i2p namespace tunnel { TunnelPool::TunnelPool (i2p::data::LocalDestination& localDestination, int numHops, int numTunnels): - m_LocalDestination (localDestination), m_NumHops (numHops), m_NumTunnels (numTunnels), m_LastOutboundTunnel (nullptr) + m_LocalDestination (localDestination), m_NumHops (numHops), m_NumTunnels (numTunnels) { } @@ -34,8 +34,10 @@ namespace tunnel { expiredTunnel->SetTunnelPool (nullptr); m_InboundTunnels.erase (expiredTunnel); + for (auto it: m_Tests) + if (it.second.second == expiredTunnel) it.second.second = nullptr; + } - m_LocalDestination.UpdateLeaseSet (); } void TunnelPool::TunnelCreated (OutboundTunnel * createdTunnel) @@ -49,9 +51,9 @@ namespace tunnel { expiredTunnel->SetTunnelPool (nullptr); m_OutboundTunnels.erase (expiredTunnel); + for (auto it: m_Tests) + if (it.second.first == expiredTunnel) it.second.first = nullptr; } - if (expiredTunnel == m_LastOutboundTunnel) - m_LastOutboundTunnel = nullptr; } std::vector TunnelPool::GetInboundTunnels (int num) const @@ -72,19 +74,7 @@ namespace tunnel OutboundTunnel * TunnelPool::GetNextOutboundTunnel () { - if (m_OutboundTunnels.empty ()) return nullptr; - auto tunnel = *m_OutboundTunnels.begin (); - if (m_LastOutboundTunnel && tunnel == m_LastOutboundTunnel) - { - for (auto it: m_OutboundTunnels) - if (it != m_LastOutboundTunnel && !it->IsFailed ()) - { - tunnel = it; - break; - } - } - m_LastOutboundTunnel = tunnel; - return tunnel; + return GetNextTunnel (m_OutboundTunnels); } InboundTunnel * TunnelPool::GetNextInboundTunnel () @@ -118,9 +108,27 @@ namespace tunnel for (auto it: m_Tests) { LogPrint ("Tunnel test ", (int)it.first, " failed"); - // both outbound and inbound tunnels considered as invalid - it.second.first->SetFailed (true); - it.second.second->SetFailed (true); + // if test failed again with another tunnel we consider it failed + if (it.second.first) + { + if (it.second.first->GetState () == eTunnelStateTestFailed) + { + it.second.first->SetState (eTunnelStateFailed); + m_OutboundTunnels.erase (it.second.first); + } + else + it.second.first->SetState (eTunnelStateTestFailed); + } + if (it.second.second) + { + if (it.second.second->GetState () == eTunnelStateTestFailed) + { + it.second.second->SetState (eTunnelStateFailed); + m_InboundTunnels.erase (it.second.second); + } + else + it.second.second->SetState (eTunnelStateTestFailed); + } } m_Tests.clear (); auto it1 = m_OutboundTunnels.begin (); @@ -139,7 +147,7 @@ namespace tunnel it2++; } if (!failed) - { + { uint32_t msgID = rnd.GenerateWord32 (); m_Tests[msgID] = std::make_pair (*it1, *it2); (*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (), @@ -155,6 +163,9 @@ namespace tunnel auto it = m_Tests.find (be32toh (deliveryStatus->msgID)); if (it != m_Tests.end ()) { + // restore from test failed state if any + it->second.first->SetState (eTunnelStateEstablished); + it->second.second->SetState (eTunnelStateEstablished); LogPrint ("Tunnel test ", it->first, " successive. ", i2p::util::GetMillisecondsSinceEpoch () - be64toh (deliveryStatus->timestamp), " milliseconds"); m_Tests.erase (it); } @@ -168,17 +179,28 @@ namespace tunnel OutboundTunnel * outboundTunnel = m_OutboundTunnels.size () > 0 ? *m_OutboundTunnels.begin () : tunnels.GetNextOutboundTunnel (); LogPrint ("Creating destination inbound tunnel..."); - auto firstHop = i2p::data::netdb.GetRandomRouter (outboundTunnel ? outboundTunnel->GetEndpointRouter () : nullptr); - auto secondHop = outboundTunnel ? outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router : nullptr; - if (!secondHop || secondHop->GetIdentHash () == i2p::context.GetIdentHash ()) - secondHop = i2p::data::netdb.GetRandomRouter (firstHop); - auto * tunnel = tunnels.CreateTunnel ( - new TunnelConfig (std::vector - { - firstHop, - secondHop - }), - outboundTunnel); + const i2p::data::RouterInfo * prevHop = &i2p::context.GetRouterInfo (); + std::vector hops; + int numHops = m_NumHops; + if (outboundTunnel) + { + // last hop + auto hop = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router; + if (hop->GetIdentHash () != i2p::context.GetIdentHash ()) // outbound shouldn't be zero-hop tunnel + { + prevHop = hop; + hops.push_back (prevHop); + numHops--; + } + } + for (int i = 0; i < numHops; i++) + { + auto hop = i2p::data::netdb.GetRandomRouter (prevHop); + prevHop = hop; + hops.push_back (hop); + } + std::reverse (hops.begin (), hops.end ()); + auto * tunnel = tunnels.CreateTunnel (new TunnelConfig (hops), outboundTunnel); tunnel->SetTunnelPool (this); } diff --git a/TunnelPool.h b/TunnelPool.h index 27848bfb..21b8f6c5 100644 --- a/TunnelPool.h +++ b/TunnelPool.h @@ -28,6 +28,7 @@ namespace tunnel const uint8_t * GetEncryptionPrivateKey () const { return m_LocalDestination.GetEncryptionPrivateKey (); }; const uint8_t * GetEncryptionPublicKey () const { return m_LocalDestination.GetEncryptionPublicKey (); }; + const i2p::data::LocalDestination& GetLocalDestination () const { return m_LocalDestination; }; bool IsExploratory () const { return m_LocalDestination.GetIdentHash () == i2p::context.GetIdentHash (); }; void CreateTunnels (); @@ -57,7 +58,6 @@ namespace tunnel std::set m_InboundTunnels; // recent tunnel appears first std::set m_OutboundTunnels; std::map > m_Tests; - OutboundTunnel * m_LastOutboundTunnel; }; } } diff --git a/Win32/i2pd.vcxproj b/Win32/i2pd.vcxproj index 45f10b29..242e366c 100644 --- a/Win32/i2pd.vcxproj +++ b/Win32/i2pd.vcxproj @@ -43,6 +43,7 @@ + @@ -80,6 +81,7 @@ + @@ -156,4 +158,4 @@ - \ No newline at end of file + diff --git a/Win32/i2pd.vcxproj.filters b/Win32/i2pd.vcxproj.filters index a408cc01..eeacc6da 100644 --- a/Win32/i2pd.vcxproj.filters +++ b/Win32/i2pd.vcxproj.filters @@ -75,6 +75,9 @@ Source Files + + Source Files + Source Files @@ -194,6 +197,9 @@ Header Files + + Header Files + Header Files @@ -225,4 +231,4 @@ Header Files - \ No newline at end of file + diff --git a/aes.cpp b/aes.cpp index 518d5c58..458654ec 100644 --- a/aes.cpp +++ b/aes.cpp @@ -313,6 +313,7 @@ namespace crypto ); #else m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv + m_LayerEncryption.SetIV (payload); m_LayerEncryption.Encrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv #endif @@ -348,6 +349,7 @@ namespace crypto ); #else m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv + m_LayerDecryption.SetIV (payload); m_LayerDecryption.Decrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv #endif diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index ac114a45..641575bc 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -38,7 +38,9 @@ set ( SOURCES TunnelEndpoint.cpp TunnelPool.cpp util.cpp + aes.cpp Daemon.cpp + SOCKS.cpp ) set ( HEADERS @@ -67,7 +69,9 @@ set ( HEADERS TunnelEndpoint.h TunnelPool.h util.h + aes.h Daemon.h + SOCKS.h ) if (WIN32) diff --git a/build/i2pd.pro b/build/i2pd.pro deleted file mode 100644 index 2200ea89..00000000 --- a/build/i2pd.pro +++ /dev/null @@ -1,83 +0,0 @@ -TEMPLATE = app -CONFIG += console -CONFIG -= app_bundle -CONFIG -= qt - -TARGET = ./../../i2pd_qt - -QMAKE_CXXFLAGS += -std=c++0x - -LIBS += -lcrypto++ -LIBS += \ - -lboost_system\ - -lboost_filesystem\ - -lboost_regex\ - -lboost_program_options\ - -lpthread - -SOURCES += \ - ../LeaseSet.cpp \ - ../i2p.cpp \ - ../HTTPServer.cpp \ - ../HTTPProxy.cpp \ - ../Garlic.cpp \ - ../base64.cpp \ - ../AddressBook.cpp \ - ../util.cpp \ - ../UPnP.cpp \ - ../TunnelPool.cpp \ - ../TunnelGateway.cpp \ - ../TunnelEndpoint.cpp \ - ../Tunnel.cpp \ - ../Transports.cpp \ - ../TransitTunnel.cpp \ - ../Streaming.cpp \ - ../SSU.cpp \ - ../RouterInfo.cpp \ - ../RouterContext.cpp \ - ../Reseed.cpp \ - ../NTCPSession.cpp \ - ../NetDb.cpp \ - ../Log.cpp \ - ../Identity.cpp \ - ../I2NPProtocol.cpp - -HEADERS += \ - ../LeaseSet.h \ - ../Identity.h \ - ../HTTPServer.h \ - ../HTTPProxy.h \ - ../hmac.h \ - ../Garlic.h \ - ../ElGamal.h \ - ../CryptoConst.h \ - ../base64.h \ - ../AddressBook.h \ - ../util.h \ - ../UPnP.h \ - ../TunnelPool.h \ - ../TunnelGateway.h \ - ../TunnelEndpoint.h \ - ../TunnelConfig.h \ - ../TunnelBase.h \ - ../Tunnel.h \ - ../Transports.h \ - ../TransitTunnel.h \ - ../Timestamp.h \ - ../Streaming.h \ - ../SSU.h \ - ../RouterInfo.h \ - ../RouterContext.h \ - ../Reseed.h \ - ../Queue.h \ - ../NTCPSession.h \ - ../NetDb.h \ - ../Log.h \ - ../LittleBigEndian.h \ - ../I2PEndian.h \ - ../I2NPProtocol.h - -OTHER_FILES += \ - ../README.md \ - ../Makefile \ - ../LICENSE diff --git a/contrib/certificates/reseed/backup_at_mail.i2p.crt b/contrib/certificates/reseed/backup_at_mail.i2p.crt new file mode 100644 index 00000000..73b08eaa --- /dev/null +++ b/contrib/certificates/reseed/backup_at_mail.i2p.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFfTCCA2WgAwIBAgIEOprmhjANBgkqhkiG9w0BAQ0FADBvMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEYMBYGA1UEAwwPYmFja3VwQG1haWwu +aTJwMB4XDTEzMTAxMzEzNDQ1NVoXDTIzMTAxMzEzNDQ1NVowbzELMAkGA1UEBhMC +WFgxCzAJBgNVBAgTAlhYMQswCQYDVQQHEwJYWDEeMBwGA1UEChMVSTJQIEFub255 +bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGDAWBgNVBAMMD2JhY2t1cEBtYWls +LmkycDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIoAkobXwk/Enf1d +roHyqCyvcJfZJVTwb/LgYWAvCBMCr+RGqlSgtk3g69Y3I0xU08fD2kGt3r5Pwsbr +omXIbJAcccyLqmQ5QX6QgL+X9VpMDp9C4h2RogCrqLBAWw4cuZ4RS9VCpP1Yis7H +uejYqENP86p7BsRnuW/4cYnfunAdMpss4LpRGQXt1nTX+kfgCYgnKFbFqwAHt7yV +Ds+Pe6FuBHPlp+sc1amKRcUnSvhXLsv43VicnT7xYL/kUsN83wrtHA3B4aGDx3aA +3/EzuRmIXQB0BlTZILMEyYwG/nc4OsW82QYrvEZ9BIg9A4lF/wS/KZCICPxLF2zo +dGjnmlgkiA4s8eO+va/ElHyELjckVXqmG1eXHhSkEsDvOQJy01IUuwLinvq7cUbJ +HfJBZJllEg+sLDCv3FkEqN+XjBNFfQN4oNew4w6IPY6YH1INVB9LL0Cmdu4DudLv +TY8OcI8eSfez3hmm+pYQ23PJRYYnvRDnRECyIWBegkckWRh8U/WvZUYUvETK6EDl +/0KpTtfzX6MqHA5D6bTAB8Y3ijGMLrZ/B5vj5yCoZbLiGme9X2moR2k1LEhdhtzV +exsqezCpg6dn48FTX7mHjvR5/r4kz2jqBGmdPUWIIxnjFUzDUK3llVQiHihleHpe +jL4LqnhBGKWFRTaVwaIkBG4zAfIzAgMBAAGjITAfMB0GA1UdDgQWBBQNkfW7bSMl +1/4KDbgwrkf9x1Zu/TANBgkqhkiG9w0BAQ0FAAOCAgEAGg3a3rTf0EznQocmio0T +5gCoL0n8h6yKW/PyPAIELrd9wiYjhJFcWvMTcJJJnVqmAL5vpvhaAFVtAfx70MGa +0DZ7FvytK5hEfF4IqOFDyEEVGJR5rIpVK4MeI1nmwEsxdbW+FhODjtRzgYO8XBME +Xj4aY1FWg9vxc3reUj6PSFsZtsB0aLiRgL9JDovJIiRw0Uqr1v2wXBte5yVCxDge +vTREZtpK4cKetoOa68pwSXI32JwKE18j6bfdKVBCcYQKlKP/3gHGduaDrQv3w32S +DRym5s6MREeTUOtAw4wq46KpdOX8yyAqJPrCfMwS6ORd3t+egqOw0PUnsqb97w4O +lUtrRYvb2cOj60SmRx4vJvItyuHbKqIK7o2e1RcUZPXYoAVx2ww4XB2Wk4D7LSAs +cS7nLj8yAqzJ2qqtBzxu+zILJtkVa12dKF0xmS0BxBp4sCYiBtmAVE8AWQqEuSHA +FrMWqoXcjcfdvvyX487FFWWUE7ZBIn0hee2sK9J9+SPtqczJaN7TF3K3nzo65WJG +1epltmq2Ugjb67Gz7v4y7H23DJ/qhm8yLtCHTj69HTta5I08j6Kut924WLZaiMO/ +4YoEL5AE63X0sxYibKFQiq7FW5nUJA280GRlY3xSMFzlB2ggazrUV3YAWVDhfdnI +flpzWXkFM2D36OUaubfe9YY= +-----END CERTIFICATE----- diff --git a/contrib/certificates/reseed/echelon_at_mail.i2p.crt b/contrib/certificates/reseed/echelon_at_mail.i2p.crt new file mode 100644 index 00000000..52ac1c38 --- /dev/null +++ b/contrib/certificates/reseed/echelon_at_mail.i2p.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFfzCCA2egAwIBAgIEcpgq/jANBgkqhkiG9w0BAQ0FADBwMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEZMBcGA1UEAwwQZWNoZWxvbkBtYWls +LmkycDAeFw0xNDA2MjcxNTQwMTJaFw0yNDA2MjYxNTQwMTJaMHAxCzAJBgNVBAYT +AlhYMQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9u +eW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRkwFwYDVQQDDBBlY2hlbG9uQG1h +aWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgcD+2Ma/q1zo +Ae9Iurlxj6YwyUTtd6P1ctAOvw9bpgSLW0wMRnRhaCj3d0BWUOY5/42KDvX2JXiO +kz/VuYy29bMHK1pdJZuY1FGFrKudFYJ6qOr+xkiEk5YT8D/RLxWQ1oibFL18nJwd +pSlOT6XhP0uZAdrZy/CaRmIKKZwAcsdUXt+hNVVoyCJHM2x4d5eqahEgjI/39IY/ +5a3kBZDiZI55jDJKsUr4jyq392W6TY03mTeacJzIyMIW6/ut0JkphrZaRY5dtB3i +1RMUWhjuCyg+zHrETSlwIgGhuzxVJLXlSpmCk3UiCsu79lUulZ2ReuifdACJ/e3A +oet2fyjOp+siPaGzdTJ4MjAoMl0uzd1+D4tiq8ajneoEPYxhaeYjeRwPEUcihHjP +cgOKZiV/zUQPoYD3YQ4rwM07sfKLoHO+jxN21t3qXFHce6NwMuiid6mGzl5gVHvq +mt8nI3gJCIfbhUPWyUvdMtMbSHvWnKSwtLthOGLuXrwYMiV/6x5l68+y8waagjkH +fI1H/tKmUT7wcHCldxsQaXbmoEGbboEsjpcm+7+wbk5sTxkqrGxWFrMtlvnBH0fj +dQX/UeG1IPpDi2QqWmPdrIOdKng1a+CMMyDJZX0LcEBmVZzNhRKvZmqAe1vhf+LF +s8adUCnpPm1p3quLrIvoKb2YS4VIl50CAwEAAaMhMB8wHQYDVR0OBBYEFFeW8HLy +KaFZ71umI2XnnddzJO8rMA0GCSqGSIb3DQEBDQUAA4ICAQAKXytX51clQl1jYwGE +in+nUo/XdTIKXlT322SHS36Keg2SlFTnlREIFkuI5J1TM+lILxwgCm+JrN/lknd4 +ZMzJ4RGOMqBhqQG1x/Dgde52pamQqFMeLkh3GiwWYcHfekUt66PqxtQizuG4UNFc +Le98hpLNQoF2p/zW/5f4CtSs/HsO1lGlO9LB0zQtjbegmIZnwj4WOL+qpRbsDeZi +jf1gW0qyLeiQNyXW/e+sujNYe4PIioGombeKrzPoABKD0x2gsI5SVr7e8X3HgtkK +kDUXsQqevRFrifHvF1TjVC1J3YqnuTwYKXqA2d72icLp1U2OY2RFYgJPLZgbj2MK +32EZ1YW4rEf5gfPosN5NBIIsmsxfkji8vC7pe8UeJzxTjM/EuVTTiGjPZbpz/PHY +YliGKKFOe1tStq2zo7FxGRAlH9OGuKtBSw/WyN+NyTTsndOO6RXz4jIf0PBvtyjS +FoyV3W6x7R5WjjlyQOVLEgAfJkEjoACuI6rz48/FKjnyxSRlRo7+9/LfgwiU8ye3 +IuEmA0W2lSSY8lSeJA7p9utKT6zuQwCkgL69u0QSK4GD0G6dteVTlpd99c5xwgVu +cEGSP30XpQMrSknKwv2KHv7nBqRJSPO7JYMl4TjbKr8BM1q5AK8pfYPFgMjFTCwT +/hCfobYS9FLpJCFkIMcnYrhM8g== +-----END CERTIFICATE----- diff --git a/contrib/certificates/reseed/matt_at_drollette.com.crt b/contrib/certificates/reseed/matt_at_drollette.com.crt new file mode 100644 index 00000000..e490a152 --- /dev/null +++ b/contrib/certificates/reseed/matt_at_drollette.com.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIEB52rdjANBgkqhkiG9w0BAQ0FADByMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEbMBkGA1UEAwwSbWF0dEBkcm9sbGV0 +dGUuY29tMB4XDTE0MDcyMTEzMjYxM1oXDTI0MDcyMDEzMjYxM1owcjELMAkGA1UE +BhMCWFgxCzAJBgNVBAgTAlhYMQswCQYDVQQHEwJYWDEeMBwGA1UEChMVSTJQIEFu +b255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGzAZBgNVBAMMEm1hdHRAZHJv +bGxldHRlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL5M9wKT +csNLg4EA3fW7LleTQdrm3stPnoUvFmsNZHGgsKt1Nc1qCNis3kr2QEY+4Z398U7r +7xGEQFa7D/9SPHf6n1uVXc9DIcmwBtEB0FPB1XPFp2h00ZXIv24yiLN3GQT1woAM +yEbBWsUgn8K/iMBeA5dU2vPwAbGO/0ibD62frgGdYqU2EeiJ/U6vBmKxvC+q2noL +gnyfQJEJANXgf+Cw/gBaS6yn5ZsYcenLNenID2TQKQ6Q/NxYrDYRdWdId29iwldt +dmNSmASv8C7g9d/isZkpmtYNkE4J4m0W9wKziOoyvLSMo8ec67QmCKaPaYKTHTjx +aUuja02+mnlV4DSdZo6nPkSdokRY0+5e6q7+dIPefu8ealGEAE5oedEfl5iM5Fnz +phTR+ePodBK3sB+bMi1NMppbWugpFpdqs1hg2KNKSSG8C4/eTqf2nnlDiVvvFANc +imt6tk0pZcKqveRiDSgI8mTzTcrNgVClsCLoInY5Vab7onZjY9bGijPQ2i1P6+qu +5G6LiLFW7xFq2BcX1DnTztcJ8Yu9NYHhR21J6u7Dr8YHntes3mnth1F0BX3FVA1s +9SaE9/pNhdqap9owpEhNoE1Ke3LorVLL8jyQsqgRHx8VdhWdi9Ao0mzzeI9HYX0j +nZ7uXK5DqGG74K6eWoS9jZSDJLj3IBkIr3B/AgMBAAGjITAfMB0GA1UdDgQWBBTK +YjH+9Jv82Zqi86r95/1sXUCOnDANBgkqhkiG9w0BAQ0FAAOCAgEAsDyl3dS/5pR1 +iDN0zE70HN1Sjv55c5um6N39rgz8JSObbAMihhpjRXPR6yl0PdfVcswdCuEaaykp +ppPNY5ObqZIdqI92XOaOhSA3AkZwZffbwaoXFYiawq1aQG1HP7oxXzWwbnbPOxgz +6ThNP5DJan53Mk8TAhxoJkEJxVlMwIiC+QEgqDNYrP8oNOR2J1EXgzsHheEKObyP +xTwRYFqZU/7BQlFeB0LG1LIy9zXAHlb/XIor10w6ChPDW7DiDwGq3zDJw1d8eiUn +RoPRmFjTqn+3rGaEkk+vUFHoWo7cLCEIC3+P9wlY4Kel+ldXMmuJ+BZ1glFXeO3L +VO85n7iVIyBbwo7RLtNaBvrRQIEG3ld5UOKklLlWwhrX/FXksEhdFvmuF9sbiYNr +cg81sbwZlX7Gi7VicXkykFFXwRRr3UblDtfeevouxk4nMVzcDsmzGeAZKQBvcxHa +Pzc70YwnVRqTc87c0bEwPoxK1Vb26+DILyDjKb/AkTw/rwj6vcJZP2ad+hpiz5Ka +nlbY2cI3JJb0TQiDiOIk+xFqC5oHUTSEmfqA6sA5o/RqdwDpkfpgI5mCwhYzDSLD +jfS+263ylhanl7oz0sM+GtH63owVbYJAFT2EozT9siTIErvJESL4Z80yUQG63d/7 +fss8T6gOo19esb/KEMZGZE4pAApakWM= +-----END CERTIFICATE----- diff --git a/contrib/certificates/reseed/meeh_at_mail.i2p.crt b/contrib/certificates/reseed/meeh_at_mail.i2p.crt new file mode 100644 index 00000000..6014c96f --- /dev/null +++ b/contrib/certificates/reseed/meeh_at_mail.i2p.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFeTCCA2GgAwIBAgIEZZozujANBgkqhkiG9w0BAQ0FADBtMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwNbWVlaEBtYWlsLmky +cDAeFw0xNDA2MjgyMjQ5MDlaFw0yNDA2MjcyMjQ5MDlaMG0xCzAJBgNVBAYTAlhY +MQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1v +dXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1tZWVoQG1haWwuaTJw +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnVnmPE4uUvCky0yCnnVH +cJEDqzwDPupx0zr0YDlhZk5VOPPecx5haayJ/V6nXPc1aVVWn+CHfedcF2aBgN4K +5aBueS/l6l5WHcv02DofAqlTmyAws3oQeR1qoTuW24cKRtLR7h5bxv63f6bgp6e+ +RihFNez6UxErnRPuJOJEO2Im6EgVp6fz7tQ7R35zxAUeES2YILPySvzy2vYm/EEG +jXX7Ap2A5svVo90xCMOeUZ/55vLsjyIshN+tV87U4xwvAkUmwsmWVHm3BQpHkI6z +zMJie6epB8Bqm0GYm0EcElJH4OCxGTvDLoghpswbuUO7iy3JSfoL7ZCnoiQdK9K4 +yVVChj8lG+r7KaTowK96iZep+sZefjOt5VFGuW2Fi/WBv3ldiLlJAo/ZfrUM4+vG +fyNBXbl6bX87uTCGOT1p3dazo+zJMsAZ+Y93DlM/mDEWFa1kKNrs74syzaWEqF4L +KQE6VoYn80OOzafSigTVQgSwUtQtB0XGhMzJhyxU2XHWe1LFIy7Pta0B+lDiZj7c +I8nXxYjsDfEu/Elj/Ra9N6bH0awmgB5JDa+Tbir+oEM5SyDfpSaCGuatdGxjweGI +kVmFU0SqCZV/8TXbIu6MUVzTZMZVT94edifFSRad4fqw7eZbSXlPu++3d1/btn6h +ibM04nkv0mm+FxCKB/wdAkECAwEAAaMhMB8wHQYDVR0OBBYEFO7jIkSRkoXyJcho +9/Q0gDOINa5EMA0GCSqGSIb3DQEBDQUAA4ICAQBzfWO7+8HWOKLaYWToJ6XZbpNF +3wXv1yC4W/HRR80m4JSsq9r0d7838Nvd7vLVP6MY6MaVb/JnV76FdQ5WQ6ticD0Y +o3zmpqqbKVSspN0lrkig4surT88AjfVQz/vEIzKNQEbpzc3hC2LCiE2u+cK/ix4j +b9RohnaPvwLnew5RNQRpcmk+XejaNITISr2yQIwXL7TEYy8HdGCfzFSSFhKe9vkb +GsWS5ASrUzRoprswmlgRe8gEHI+d51Z7mWgna0/5mBz9bH/3QXtpxlLWm3bVV+kt +pZjQDTHE0GqG2YsD1Gmp4LU/JFhCojMTtiPCXmr9KFtpiVlx06DuKm5PC8Ak+5w+ +m/DQYYfv9z+AA5Y430bjnzwg67bhqVyyek4wcDQinFswv3h4bIB7CJujDcEqXXza +lhG1ufPPCUTMrVjh7AShohZraqlSlyQPY9vEppLwD4W1d+MqDHM7ljOH7gQYaUPi +wE30AdXEOxLZcT3aRKxkKf2esNofSuUC/+NXQvPjpuI4UJKO3eegi+M9dbnKoNWs +MPPLPpycecWPheFYM5K6Ao63cjlUY2wYwCfDTFgjA5q8i/Rp7i6Z6fLE3YWJ4VdR +WOFB7hlluQ//jMW6M1qz6IYXmlUjcXl81VEvlOH/QBNrPvX3I3SYXYgVRnVGUudB +o3eNsanvTU+TIFBh2Q== +-----END CERTIFICATE----- diff --git a/contrib/certificates/reseed/sindu_at_mail.i2p.crt b/contrib/certificates/reseed/sindu_at_mail.i2p.crt new file mode 100644 index 00000000..be1010f9 --- /dev/null +++ b/contrib/certificates/reseed/sindu_at_mail.i2p.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFezCCA2OgAwIBAgIEPSs1SjANBgkqhkiG9w0BAQ0FADBuMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOc2luZHVAbWFpbC5p +MnAwHhcNMTQwNzIxMDAwNjUwWhcNMjQwNzIwMDAwNjUwWjBuMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOc2luZHVAbWFpbC5p +MnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnYMNclgj1gIJfot6f +65jbcXpcqf9hhL/uYiU4+uxVevWyJvNHpMzhPWNN4l3HihJJsINsPs/MsZ83Guva +GW5S/93I617kyjs/ZVpEtfABGewho0m9VCBV2/N1mJpHvvR+9OR+YVuWlTB/8sTG +2smdRj/dkKvewN5PSTQH350yT18NR/DmZUU1Iwa7vrNw8ol3rP3qx9UGpFN3JE7V +Q9cA1nktMiFUm76eOPOoln04WDqW2rvArXzvhSApvt0JsLBrZDzM3cx2Rc2UdjIC +h+Ha+G4CLjszfZfQAFJYPred38Gg6wuXiza/wCBSPiB92i94hIQF/OSeukaMiqwG +dRAcBT84/U9bddqHlIICw14PkNHOGUyJGjGKWQl/2bLX43ghWkUJmsTXS3iVcOTc +gb/7MoCRBdL0q2GyEJXuAoKXD9VqD3g+EdcBTQxS9lhZ0iTR7423pg6FP43VMEUC +HUi/BOX1tCY6iRzD1Su6ISIx7klH/sAWWa+SybLFXWtZJxHXXJICiBHJWRbWgtlu +5V+at66yg/LNpyfW3Am08gDV0kiWUBN2Ct4TX9PAQmNDisNgi2AzdZHIfX6tRpU8 +UnNcnZGOh4+HXQwJtI0y83C8TsXJUFYfGFWqXN69sMEmgtX8/w+YUqjtb2GcX1HN +6z9u9lH40JCFHTA/clPqOSQ+MQIDAQABoyEwHzAdBgNVHQ4EFgQU4R6x7ArVpSVs +b8VTBXmodXzyraEwDQYJKoZIhvcNAQENBQADggIBAJEHLSDBRU2x6EalmN2W952p +MEO5lGD+ZfUVK0c44t1O53naffwZx9QmDmrC4TjeQrLOpAXLQ8GJHAGeZVmYRgkf +OioKde5uuqVcxqNxArO8VyYGwsuNVPCaBV+SyIO+EmWogidSIrOP2WsRRS2NBhLV +2dp3TvMeod9bPwRl00guvv9iqL0UVSpQSlfGkAQTVpyADOaQHOzeoCpmtPOfB6OK +syB/Z/6HElKoUbvhynaASLgmo3wM93PVJQ2Ho294bQHtDl2qcOksJQvWfCgi7Zrt +KuHaM/a2kItzI6JmyNFXgsKQSDJ4UvoppppgD7K48zOtSipGuZAADC5w5HdVvIGJ +1Czva8kTcmC6AMc+4tACGqYZEAEokkeXn+pIIqKVj2eQukT/0dLGGHbKmxp3Z0f2 +pIH2Draq8JPdacr9P/xqEWUuViaOuC5OBjY8Fg3fmVCpwefIuk+DBhbJjEugB0Cu +brJpqNznoYahkbyAXIA8T+QJYMhoGWmaIcaPWK6K3nArvaxzwJbb9Egyivhyp9Rr +r2QMEZ+cPO8p1mEhKpL/wGqAzYyla8SJ06PzLc1lQeGiClu1nbZj5AgkZ1DLa8SD +iO7+e6rS0q1bzc7smE5JzZRiOVqKij/ReKa2uebLLI4wgAhz5ymaD1HfZY+3dV9T +WX89Xn2UyQf5kHifiDKL +-----END CERTIFICATE----- diff --git a/contrib/certificates/reseed/swat_at_mail.i2p.crt b/contrib/certificates/reseed/swat_at_mail.i2p.crt new file mode 100644 index 00000000..60659598 --- /dev/null +++ b/contrib/certificates/reseed/swat_at_mail.i2p.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVjCCAz6gAwIBAgIEU71jgDANBgkqhkiG9w0BAQ0FADBtMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwNc3dhdEBtYWlsLmky +cDAeFw0xNDA3MDkxNTQ1MDRaFw0yNDA3MDgxNTQ1MDRaMG0xCzAJBgNVBAYTAlhY +MQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1v +dXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1zd2F0QG1haWwuaTJw +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjSj53hsbTqtzbnlf5LbR +HmfdC2br9QZaB9e5IQKprlTptdzqTrt2LRS6ZaJ06BKJgX3AfLflvyeUDUPoyg63 +I9a1kb1AsrcxvMkHXTUwPaO09caO5/CiQ3zx/iuTl4e0MmGe3cz7jsvZNdOVH0ba +B691GB2UBq2QjobGx01qjWtACCmoQIcEur2ns/l+VzAextBL70dSPN6EJAonQnWc +JvHf1vhXp5DWasaIovm8haNo48QpCo7NllsAjiONQM9rrJITvzFG9hX9cv/B1Kr4 +LCebTXv58ViXXFsnxYhktAFwP33fn1eCLraJ/BpaDR4+s3ovMC/7S+g5//+sQTd1 +pR/kXx4BmZWZdzs083Z/2skQON75j/qnMhUQqpFCqUImm4lOhlIGbzFJ4GQM6VCR +V4BbvC3XuDc6vlivLzWpUEU7Kc6YnfGgi2G//ZCj2CAoR7qZs/n9997C8oAvGY5z +XGVC/GqIFHuFvnDfPDvxGovYjLJ0KrNtAmp2Rb5812glnVdPwbRYRUBg3ICbNey3 +rmGPURDq0aHMTzX4gtM+/hCYYVnkzNMQvYuw9EZLZrK/XdM1a0U4kajZSKKJsTmW +uQwXSUVjTKQh//yL4zPoELucFk5r7apLePEm6aCeWuY2wVkR8KEFgNanwDckWQAm +Lk9r2t+Y/l2jS2NqBWFyr+cCAwEAATANBgkqhkiG9w0BAQ0FAAOCAgEAgFSquj/0 +iZYpFI1XarSIVpGMo0WLAmb9GZCn5yoXSeE6eypI/hHhXA4Bjdk2Ae33pXPNcCV8 +oT/gHj8943Wx7CTxty2zHzIsd92/HG2EG6U/HPp5l7yIJQaWoe/9tjQoaBhipZOK ++MiytkoBWkyXFqXnKQPExiadWB8axHtt66vrikOcSx6Ur3u5DPKybvY4fsuvo4+I +cLLgoueFm6I1WhmkVmjtm4k2yZ/Z3NEYjg52rv8NuYhRwK2JrQeRzMZv/zt5KhOt +05woHrzymjfFBu0M8uxX7EGZBIsc8zcEY7JL/NSMArw/QCgLU5bQF6+CsyxWUkt1 +obMRXU1oS9GjC/1F0kw52NOz2qzBn9tZBc1zs8+GLpYBUf9KiUMFOfJpkr706VqC +orgxRYwncicq+de2PlesxJb3DNPFuAzUNzAqxcVYDoFPAiL1zCEl0nhBrbN+x93X +ojTfV3UlbMjMkQKveYJxsi5/+jO1dHIkXpzK4bwFwHmJ2RCa6PualWhuXldX6mR+ +APoY6xeoPRlyKk+POrSwU+hywUudyPuFyzDMo8n1w4CyqL+/ky3YsLfGBM1phbb2 +GEnZ0J1HW34Pnie1rzaCak+3RfaZsImCwh1xXl/H7Ka9bLeUIfOuipSSroctdaiG +84wIiEjxgjW2ldM37gTX2XtE/blB1YPIZ5U= +-----END CERTIFICATE----- diff --git a/contrib/certificates/router/killyourtv_at_mail.i2p.crt b/contrib/certificates/router/killyourtv_at_mail.i2p.crt new file mode 100644 index 00000000..597f455f --- /dev/null +++ b/contrib/certificates/router/killyourtv_at_mail.i2p.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFhTCCA22gAwIBAgIELuRWgDANBgkqhkiG9w0BAQ0FADBzMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEcMBoGA1UEAwwTa2lsbHlvdXJ0dkBt +YWlsLmkycDAeFw0xMzEwMDYyMTM5MzFaFw0yMzEwMDYyMTM5MzFaMHMxCzAJBgNV +BAYTAlhYMQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBB +bm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRwwGgYDVQQDDBNraWxseW91 +cnR2QG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAig3u +niLWm0y/TFJtciHgmWUt20FOdQrxkiSZ87G8xjuGfq7TbGIiVDn7pQZcHidpq+Dk +47sm+Swqhb4psSijj0AXUEVKlV39jF5IZE+VUgmEtMqQbnBkWudaTJPWcEe9T/Kd +8Oz2jgsnrD/EGVTMKBBjt/gk8VqTWvpCdCF1GhqcCeUTFHzjhN9jtoRCaJ2DClpO +Px+86+d3s9PqUFo8gcD/dbbyJCMqUCMBLtIy/Ooouxb9cfWtXfyOlphU+enmdvuA +0BDewb9pOJg2/kVd9/9moDWcBGChLOlfSlxpDwyUtcclcpvwnG7c6o4or6gqLeOf +AbCpse623utV7fWlFWG7M4AQ/2emhhe4YoMJQnflydzV8bPRJxRTeW1j/9UfpvLT +nO5LHp0oBXE0GqAPjxuAr+r5IDXFbkKYNjK5oWQB/Ul3LkexulYdCzHWbGd1Ja5b +sbiOy6t/hH6G8DD75HYb+PQZaNZWBv90EyOq1JDSUPw6nxVbhiBldi3ipc8/1X51 +FbzBqJ+QO1XKrKqxWxBKoTekuy38KRzsmkSCpY+WJ9f0gLOKtxzVO2HNNqqVFGQf +RGIbrNA0JSRQ1fgelccfrcRIXIZ3B8Tk/wxCIzCY6Yvg2jezz2xJkVdqOUsznS2v ++xJe67PYIAeMVtcfO4kmuCvyIYhsUEpob2n/5lkCAwEAAaMhMB8wHQYDVR0OBBYE +FCLneov6QMtvra5FSoSLhdymi++rMA0GCSqGSIb3DQEBDQUAA4ICAQAIcqbiwjdQ +M9VlGBiHe5eVsL6OM9zfRqR1wnRg4Q6ce65XDfEOYleBWaaNJA4BdykcA4fkUN1h +M2D9FDQScsyPTOuzJ6o75TYh0JOtF51yCi9iuemcosxAwsm90ZXGuMDfDYeyND5c +PAkWfyCP+jwLYbNo/hkNqyv+XWHXPQmT2adRnPXINVUQuBxVPC//C9wv2uDYWhgS +f8M425VPp4/R/uks9mlzTx08DwacvouD0YOC+HZE4sWq+2smgeBInMiyr/THYzl+ +baMtYgVs8IKUD2gtjfXZoaQNg3eq5SedSf/5F0S/LCdu9/ccQ8CzSEoVTiQFtO78 +SaU37xai8+QTSVpPuINigxCoXmkubBd+voEmWRcBd/XB5L+u+MFU/jXyyBj2BXVj +6agqVzY53KVYt23/63QliAUWyxT+ns9gRxVN1jrMhHdiDwsdT4NbzHxg1Su4eiHv +C/wjD3Dga0BRTEGylpHZGzb1U1rZRHM3ho3f1QkmRPPLcBUMTyUTxJm+GEeuhPvp ++TBf3Kg/YkdpnEMlagqcyHuIrf3m8Z/pTmpOIbekJWbbA7tluvWbMWw2ARB7dUOE +fHYVISh0DTw2oVXxM82/q8XXHnhEXv2nW3K40x1VabxUN+sF4M/7YA8nJqwsPJei +749STYJRfZXdIe69M9zpM5unxENAsiPJgQ== +-----END CERTIFICATE----- diff --git a/contrib/certificates/router/str4d_at_mail.i2p.crt b/contrib/certificates/router/str4d_at_mail.i2p.crt new file mode 100644 index 00000000..b01c7e32 --- /dev/null +++ b/contrib/certificates/router/str4d_at_mail.i2p.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFezCCA2OgAwIBAgIEHLJfZzANBgkqhkiG9w0BAQ0FADBuMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOc3RyNGRAbWFpbC5p +MnAwHhcNMTMxMDI2MTExODQxWhcNMjMxMDI2MTExODQxWjBuMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOc3RyNGRAbWFpbC5p +MnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvw0vTay1IPOgxvwe8 +yt5jGakha20kw9qDb6zbEL87EWEkeOzdu7iUC69lkxVP9Ws8EbLtkeMf/CXg6CC1 +e+w8WpOHj5prOsiOlrIO+2I1tKMaMUuJDX2wK4I5ZSw/Kieimh9xqOBZknDmtwjw +2HPW8rpxMqrScaGAP6sQD8Gh4XKKkLogfxYPzF8NnC6O8vBkFKVU2WSVZ0jPAQfv +6luPdA+5lES+5UPWr9Yhv/CX4siGKUTxchqJRf2VU4o5BzzXae4asVA/NY7lKgEw +eDDufbm0mRFWP4mbmXRlODuJ8GMnJbMQkNcAvZUnUcvpSTnGnIvxyxtXP5P6ic8V +3b9HV2eIsbfO1xrgyr6/9qgGpXcdDJejhvNg6fZgQeO40bOGQYwV8bNvsNQHqnZl +KsVhsMQkOubMxcHTBadcifi8PmdeJ5hxyyqJmyrwkmg2ijnN521M6YkoBzl+8VAi +zLmqKZfvN5t+pb9PZ3U3jHfkeIEwDRYRAOsvVqch5+ZfSv8x/Te6o15zDKPJQtWK +ty42GV1vERw30oSZQdrRRy/+4+HSRs3/Zb368OdAbcr+f/xPvwceYGWPeNNIoZ/x +xkIQE3xgEK+eJyPM9McjlCAezZZclT7fWfiEYNJAiS3fGALi+a+cGYWWULxCXpz+ +y397OHhZBhnh7D9K8aPePB8tCwIDAQABoyEwHzAdBgNVHQ4EFgQUezvGHq3h1gbC +Hs2LLVoll5fIUWMwDQYJKoZIhvcNAQENBQADggIBAF7SG1WBcE1r5eyTp/BLFZfG +iPtvqu+B1L2HutPum/Xf8A5fxR4kcKAKpVdu6vnDzCRAsAC9YvyETgAzI2nfVgLk +l9YZ31tSi6qxnMsQsV5o9lt/q2Rvsf2Zi/Ir8AlWtvnP8YG0Aj/8AG8MyhMLaIdj +M2FuakPs8RqEjoJL9dTOC9VTQpNTwBH9guP9UalWYwlkaXDzMoyO4nswT/GpCpg8 +4m4RO6grzdsEIamD/PCBM5f/vq+y08GaqfXpX9+8CbaX3tdzd3x48wPphmdpkptk +aRELIpLJZiK+Mos7W+0ZS8SHxGDIosjqVsgbZPmk12+VBcVgLOr8W1D7osS4OY59 +2GMUVV/GhoDh8wR/Td5wpZlcPE0NWmljjVg9+1E8ePAyMZy+U1KCiMlRVdRy518O +dOzzUUQGqGQHosRrH0ypS3MGbMLmbuWFRiz7q/3mUmW2xikH9I1t/6ZMNUvh+IWL +kGAaEf2JIv/D8+QsC0Un1W09DgvYz7qmKSeHhBixlLe68vgXtz/Fa+rRMsmPrueo +4wk/u/VyILo0BJP860APJMZbm+DPfGhV9DF9L5Gx9+d/BlduBVGHc+AQSWbU70dS +eH4/rgUYRikWlgwUxjY8/QQTlfx5xl28tG0xdO9libN22z7UwTGfm48BQIdrTyER +hqQ7usTy3oaWD85MbJ0q +-----END CERTIFICATE----- diff --git a/contrib/certificates/router/zzz_at_mail.i2p.crt b/contrib/certificates/router/zzz_at_mail.i2p.crt new file mode 100644 index 00000000..2d6fcba6 --- /dev/null +++ b/contrib/certificates/router/zzz_at_mail.i2p.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFdzCCA1+gAwIBAgIEcwrwsjANBgkqhkiG9w0BAQ0FADBsMQswCQYDVQQGEwJY +WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt +b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEVMBMGA1UEAwwMenp6QG1haWwuaTJw +MB4XDTEzMDkzMDE3NDEyNVoXDTIzMDkzMDE3NDEyNVowbDELMAkGA1UEBhMCWFgx +CzAJBgNVBAgTAlhYMQswCQYDVQQHEwJYWDEeMBwGA1UEChMVSTJQIEFub255bW91 +cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxFTATBgNVBAMMDHp6ekBtYWlsLmkycDCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJV4ptvhlfrcize9/ARz4lUy +iLtLMSvSST1BdZjLJTwus05EUs0oiqnv9qXYIWGRB97aKlAmqSxsn4ZgBttCgmev +IkuiZ8kbdqI5YaT98yKW5P2Prt9p9cPbnz5/qjwZ5L9W+k/Itx7bv2pkNEP0NLYo +NrgHHTb1hsyRxc0lfPYk2BwsIi8hIWBHNrRpR41EWFXfqPcdsxS8cQhxVj4zLG/R +aMm4H8T+V1R1Khl4R4qqRgXBP305xqqRoawHmZ/S9/RkF0Ji6IYwBq9iWthWol6W +sMDn1xhZk9765fk+ohAC2XWuGSFCr02JOILRV3x/8OUxT1GYgYjc7FfyWIekg/pZ +yotlhL2I3SMWOH3PdG58iDY121hq/LsSKM9aP20rwtvssnw+8Aex01YDkI3bM6yO +HNi+tRojaJcJciBWv6cuiFKvQdxj/mOhOr0u0lHLlJ4jqES8uvVJkS7X/C4BB7ra +bJYQgumZMYvVQJFIjo8vZxMXue53o65FRidvAUT29ay54UTiL7jRV9w1wHnzLapU +xT1v7kWpWJcZ1zzC8coJjW+6ijkk38cVLb80u1Q4kEbmP2rDxw6jRvmqg6DcCKjK +oqDt+XQ6P5grxAxLT+VMfB404WHHwNs6BB841//4ZnXvy3msMONY/5y0fsblURgh +IS2UG1TAjR+x7+XikGx9AgMBAAGjITAfMB0GA1UdDgQWBBSvx/fCCP8UeHwjN65p +EoHjgRfiIzANBgkqhkiG9w0BAQ0FAAOCAgEAYgVE1Aa/Ok5k+Jvujbx72bktRWXo +Y4UfbWH/426VdgqXt3n9XtJUNM2oI4ODwITM4O15SyXQTLJhnvJz5ELcJV8nqviZ +RjK2HNX1BW7IEta3tacCvVnjzZ265kCT59uW+qmd+5PiaAYI5lYUn8P6pe+6neSa +HW6ecXCrdxJetSYfUUuKeV6YHpdzfjtZClLmwl91sJUBKcjK+Q9G/cE6HnwcDH1s +uXr7SgkBt/qc/OlNuu4fnTqUA58TAumdq9cD+eLBilDFrux1HsUZMuBUp64x5oPi +gme+3VewsczfFEtrxaG6+l6UA40Lerdx9XECZcDCcFsK6MS1uQ2HYjsyZcWnNT3l +6eDNUbjrllwxDdRAk0cbWiMuc21CFq/1v2QMXk88EiBjEajqzyXUPmKzwFhit6pr +5kfjfXNq+pxQSCoaqjpzVKjb3CqMhSlC8cLgrPw6HEgGnjCy4cTLFHlVmD64M778 +tj6rE7CntcmUi8GKmZKyaMyUo3QQUcrjO5IQ4+3iGUgMkZuujyjrZiOJbvircPmK +4IQEXzJ/G00upqtqKstRybaWSbJ/k6iuturtA2n8MJiCBjhLy8dtTgDbFaDaNF7F +NHeqQjIJDLhYDy6mi4gya3A0ort777Inl/rWYLo067pYM+EWDw66GdpbEIB0Bp71 +pwvcQcjIzbUzEK0= +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/193.150.121.66.crt b/contrib/certificates/ssl/193.150.121.66.crt new file mode 100644 index 00000000..450581d2 --- /dev/null +++ b/contrib/certificates/ssl/193.150.121.66.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDgDCCAmgCCQCAKEkFUJcEezANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UEBhMC +Tk8xDTALBgNVBAgMBE9zbG8xDTALBgNVBAcMBE9zbG8xDDAKBgNVBAoMA0kyUDEM +MAoGA1UECwwDSTJQMRcwFQYDVQQDDA4xOTMuMTUwLjEyMS42NjEfMB0GCSqGSIb3 +DQEJARYQbWVlaEBpMnBtYWlsLm9yZzAeFw0xMzA2MjcxODM2MjhaFw0yMDA2MjUx +ODM2MjhaMIGBMQswCQYDVQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwE +T3NsbzEMMAoGA1UECgwDSTJQMQwwCgYDVQQLDANJMlAxFzAVBgNVBAMMDjE5My4x +NTAuMTIxLjY2MR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuBuFY4ZFvsbr5l1/s/GeUBLIWQLB +nqrRkonrwCyxgjSnnG1uz/Z5nf6QDUjiVnFKMXenLaDn4KCmEi4LjWQllhK9r6pj +BRkR7C0DTHq7WqfyvWnGSZZsOJDiH2vLlivV8N9oGdjxvv0N9No3AJcsmLYrxSLi +6/JF8xZ2HGuT/oWW6aWvpIOKpIqti865BJw5P5KgYAS24J8vHRFM3FA4dfLNTBA2 +IGqPqYLQA+2zfOC4z01aArmcYnT1iJLT7krgKnr/BXdJfGQ2GjxkRSt8IwB6WmXA +byz6QdNYM/0eubi102/zpD/DrySTU2kc8xKjknGUqBJvVdsL+iLK98uJrQIDAQAB +MA0GCSqGSIb3DQEBBQUAA4IBAQCTimMu3X7+ztXxlIFhwGh42GfMjeBYT0NHOLAy +ZtQNRqhNvkl3jZ4ERPLxP99+bcAfCX0wgVpgD32OWEZopwveRyMImP8HfFr4NnZ+ +edbM37fRYiVJv57kbi6O0rhEC7J5JF+fnCaZVLCuvYIrIXTdxTjvxuLhyan6Ej7V +7iGDJ8t16tpLVJgcXfRg+dvAa6aDOK6x3w78j0bvh6rhvpOd9sW/Nk3LBKP4Xgkx +PHkqm3hNfDIu8Hubeav9SA1kLVMS/uce52VyYMEDauObfC65ds0GRmCtYhZqMvj+ +FFCbssLraVJE9Hi/ZKGu33jNngDCG+wG+nmleksMYE1yTSRt +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/cert.smartcom.org.crt b/contrib/certificates/ssl/cert.smartcom.org.crt new file mode 100644 index 00000000..960f2657 --- /dev/null +++ b/contrib/certificates/ssl/cert.smartcom.org.crt @@ -0,0 +1,44 @@ +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg +Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 +MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi +U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh +cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk +pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf +OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C +Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT +Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi +HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM +Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w ++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ +Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 +Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B +26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID +AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j +ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js +LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM +BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy +dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh +cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh +YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg +dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp +bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ +YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT +TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ +9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 +jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW +FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz +ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 +ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L +EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu +L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC +O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V +um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh +NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/i2p-netdb.innovatio.no.crt b/contrib/certificates/ssl/i2p-netdb.innovatio.no.crt new file mode 100644 index 00000000..d9bac193 --- /dev/null +++ b/contrib/certificates/ssl/i2p-netdb.innovatio.no.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID2zCCApOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBCMR8wHQYDVQQDExZpMnAt +bmV0ZGIuaW5ub3ZhdGlvLm5vMRIwEAYDVQQKEwlJbm5vdmF0aW8xCzAJBgNVBAYT +Ak5PMCIYDzIwMTQwMTIxMDUzMzMxWhgPMjAyNDAxMTkwNTMzMzFaMEIxHzAdBgNV +BAMTFmkycC1uZXRkYi5pbm5vdmF0aW8ubm8xEjAQBgNVBAoTCUlubm92YXRpbzEL +MAkGA1UEBhMCTk8wggFSMA0GCSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQC9WVet +EFeKAHmwgTUxJ/bRI4Gtjke3uj897eeZ15Y0SiqdHzypsEIWtXqx4G3W801xZzhv +UiAculvwRY4kpv3DnQE4sNTzbkAlvC6z4+CpFM2mhZ7o+YmozrIsNmQNCsvlxqJV +AD1mzqTFl/OB7LVtLmpSSd36IQFGmsh24XXa4pVH33e+NCZIGsdVwGsa4GoRuC9a +s/DiLI+x6zYRoY9cfOF2DuuOfKNMjSl65QUe4uHZCsRTb1q08NnPIidEFHr94kZH +Hph+MQs6MUVK1eT4yYt084S3cEWmWBQZVyAvWQ9q8EW+MoniOM7bBG2Bn9wu2F5x +kAKWTYfKSStW5CKSox9VSoopiUAtEIqhwgFGTISqhQyfOfyY97X2M47wvyWsl6dE +NxTgdvLD/o24rejBAgMBAAGjeDB2MAwGA1UdEwEB/wQCMAAwIQYDVR0RBBowGIIW +aTJwLW5ldGRiLmlubm92YXRpby5ubzATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNV +HQ8BAf8EBQMDByAAMB0GA1UdDgQWBBTaTuBpTAinNiT9PfKNRdIn3HrwxTANBgkq +hkiG9w0BAQsFAAOCATEAsYtojwAHiFwUqvCMIMJa5YN0Ms/QpjqZiENuGBpxvmVF +WVImX4s8K/qoBAKED8uKcRbMQd0FeDea7kMisJt5cblDzYuSv6wfeLXYkaT8/9H2 +X1pXhO/eghJ2U42RTgBkaW3mCI8ohk/GehU4tEXnbWRPHt6XDoSYDJdf2X8BPcgB +ZE10owLCw9c80QTuU+LCvbt8/F2USyNplUrogJGThzxrxZvxjGq6EcDj0iA0RRoG +5CUNrCB+JgFc+4bagI3E5B0skk/wn3Nl7mM8/Nf8b1QENmc8eYBZx2InA9769DHL +tNxzvE+OeMNlKy4M9WvLieIh6KmpYhHBG8ubJT8X+bZpJkh4rH6RzVYiXeCpX2iL +eoeSriGO0+8CJTBRbd5cXYd/COT0iAomMTelhcGVTA== +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/i2p.feared.eu.crt b/contrib/certificates/ssl/i2p.feared.eu.crt new file mode 100644 index 00000000..628c6290 --- /dev/null +++ b/contrib/certificates/ssl/i2p.feared.eu.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDhTCCAm2gAwIBAgIJAPVgXcMcr3zqMA0GCSqGSIb3DQEBBQUAMFkxCzAJBgNV +BAYTAkVVMQ8wDQYDVQQIDAZFdXJvcGUxDDAKBgNVBAoMA0kyUDETMBEGA1UECwwK +T3V0cHJveGllczEWMBQGA1UEAwwNaTJwLmZlYXJlZC5ldTAeFw0xMjEwMjkxNzMw +MDZaFw0yMTAxMTUxNzMwMDZaMFkxCzAJBgNVBAYTAkVVMQ8wDQYDVQQIDAZFdXJv +cGUxDDAKBgNVBAoMA0kyUDETMBEGA1UECwwKT3V0cHJveGllczEWMBQGA1UEAwwN +aTJwLmZlYXJlZC5ldTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOUh +y2+6Q4RO+b5WPXX/cZ/9fiI7aWGe/C7z0083HOEqnkgGCYgxFWUCed6/eZbYoZ7/ +PV1BAuEereNwTp+Ov7fQB2H73O9sSAEejW6O4C2PZiZWaPxpZiTJNENbLOZxJnIN ++fSqmA5pqvGkYAJ2heZH4v4tayun7Vib58GWuizhzJ4EvhOrOrLq/YHrxMn++r4e +kNNbq4QzWpfxNa7ocDY9OJh5qFzuc+6wKj1m1syK6euDqs5d6X+y0aDTMgRxey2b +tkmNx9wC0flLg1oMcv9o1zN+dENy7Inkd/SqbSjLUqDTJzdq6xURVsgLoV63pb6r +B4gbGIlriYWK/mOPTTkCAwEAAaNQME4wHQYDVR0OBBYEFOI94JZ3Rb2RVmr8QjOp +u3KfVSrNMB8GA1UdIwQYMBaAFOI94JZ3Rb2RVmr8QjOpu3KfVSrNMAwGA1UdEwQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAD7bI05zg9nf9qanq4ZNw/rvEzYQRBmy +MqzZjcwBMGvbcEbS+zYAdAkfxmN3l/AT4I4z138Om0ud4ZJUQTVlRsJkMlmLD4Rt +Jbi2rl7mrY7Qupgu5hvgH+ZaEWr7LTq+tFjPycRS+zijw9NToKeAsgEex9zYIOYD +BxDUn/trvyA41ItvegWh803IsZUBb45Via+bopid9aFFkejRrck9hhcQ6fVh2yju +nuVwHrxNvGc0NmmJ7zI+nPESFS+TAYbWXikDhc5Vtyiuoz47WZU1cgXYYMejK4WA ++3GLvei7qKm4GOJSg7BngF5Iyj/n7ML1rBqTlN3KA1YOgpGCwJlKzto= +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/i2p.mooo.com.crt b/contrib/certificates/ssl/i2p.mooo.com.crt new file mode 100644 index 00000000..4be89d6a --- /dev/null +++ b/contrib/certificates/ssl/i2p.mooo.com.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDvjCCAyegAwIBAgICZhcwDQYJKoZIhvcNAQEFBQAwdTELMAkGA1UEBhMCVVMx +DTALBgNVBAgMBG5vbmUxDTALBgNVBAcMBG5vbmUxDTALBgNVBAoMBG5vbmUxDTAL +BgNVBAsMBG5vbmUxFTATBgNVBAMMDGkycC5tb29vLmNvbTETMBEGCSqGSIb3DQEJ +ARYEbm9uZTAeFw0xMTEwMjMyMTM2NDFaFw0xOTEwMjMyMTM2NDFaMGYxCzAJBgNV +BAYTAlVTMQ0wCwYDVQQIDARub25lMQ0wCwYDVQQKDARub25lMQ0wCwYDVQQLDARu +b25lMRUwEwYDVQQDDAxpMnAubW9vby5jb20xEzARBgkqhkiG9w0BCQEWBG5vbmUw +ggGPMA0GCSqGSIb3DQEBAQUAA4IBfAAwggF3AoIBbgMG1O7HRVa7UoiKbQTmKy5m +x79Na8vjD3etcOwfc4TSenQFvn+GbAWkJwKpM8uvOcgj1CxNeHWdSaeTFH1OwJsw +vl3leJ7clMdo3hpQDhPeGzBLyOiWwFHVn15YKa9xcM7S9Op5Q6rKBHUyyx1vGSz+ +/NBmkktpI6rcGFfP3ISRL0auR+db+adWv4TS6W8YiwQIVZNbSlKP6FNO9Mv1kxQZ +KoHPn8vT/LtAh1fcI6ryBuy3F5oHfbGumIwsS5dpowryFxQzwg5vtMA7AMCMKyXv +hP/W6OuaaEP5MCIxkWjQs35gOYa8eF1dLoy3AD9yVVhoNrA8Bc5FnVFJ32Qv7agy +qRY85cXBA6hT/Qzs/wWwp7WrrnZuifaSv/u/Ayi5vX42/bf86PSM2IRNIESoA98A +NFz4U2KGq9s1K2JbkQmnFy8IU0w7CMq6PvNEm/uNjSk6OE1rcCXML+EuX0zmXy8d +PjRbLzC9csSg2CqMtQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf +Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUdjuOczdG +hUpYzH0UXqKrOleT8GkwHwYDVR0jBBgwFoAU+SKWC49cM5sCodv89AFin3pkS0Yw +DQYJKoZIhvcNAQEFBQADgYEAKYyWlDIStjjbn/ZzVScKR174I8whTbdqrX/vp9dr +2hMv5m4F+aswX4Jr58WneKg2LvRaL6xEhoL7OAQ6aB/7xVSpDjIrrBLZd513NAam +X6bOPYJ6IH7Vw9ClFY3AlfzsNlgRMXno7rySKKzhg24kusNwKDH2yCphZy4BgjMn +y6A= +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/ieb9oopo.mooo.com.crt b/contrib/certificates/ssl/ieb9oopo.mooo.com.crt new file mode 100644 index 00000000..78772210 --- /dev/null +++ b/contrib/certificates/ssl/ieb9oopo.mooo.com.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIESzCCAzOgAwIBAgIJALGqvElYEEqyMA0GCSqGSIb3DQEBBQUAMIG7MQswCQYD +VQQGEwJERTEaMBgGA1UECAwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWll +Yjlvb3BvLm1vb28uY29tMRowGAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgG +A1UECwwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28u +Y29tMSAwHgYJKoZIhvcNAQkBFhFpZWI5b29wby5tb29vLmNvbTAeFw0xNDA0MTMx +NDI3MThaFw0zNDA0MDgxNDI3MThaMIG7MQswCQYDVQQGEwJERTEaMBgGA1UECAwR +aWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWllYjlvb3BvLm1vb28uY29tMRow +GAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgGA1UECwwRaWViOW9vcG8ubW9v +by5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28uY29tMSAwHgYJKoZIhvcNAQkB +FhFpZWI5b29wby5tb29vLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAN1CusoQ3OxJFTytbVMe7LPY8lnR7GIIQt5eCs0XTLl3ECclET1KLRo1c8Mv +vj5AwDRvL3Kw/oeDS+QvSRhgxG3lJ8i0soWDC/1LIX1NS/ZXG7hbycZ7YqAovCxU +958WPjUios73sAWUJrI8BbWFTYPWBB5lbyTaCooxtf6k7yB+CSwZnstEP/lbPNkf +Iupj+9B18ba21D2kQqZXyQRLX02d/rXq963BSkPX14Dxa7abw4lgDltvh2CzcoQH +VbQh3eGfPIIQGfvAAVEGsoy9fFt+xOUxp3KO7Y1VMKzegWqa2vBtWK+2nhpHfswq +eaE1qeVh12cG5kaVNP0o0hOUxkECAwEAAaNQME4wHQYDVR0OBBYEFIQ5U4EKfr0t +4L+RFe/RBFcDVoijMB8GA1UdIwQYMBaAFIQ5U4EKfr0t4L+RFe/RBFcDVoijMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGlNHzxF9tbS/Xr8jGpSdRLm +oIIoTr7+dIfFIy2TMAow0+gx1qEtWASUYIwbCP5mdMfhUjL8POfSwtTvgjw3LMoM +2zsGBvgGWs6VJbMPAgkgfsyjdJTM/IOiJtze6degn2bdZvAr1XiInLGMRMko7WyE +QQ1WJPcTUt8rNYVaCkq3CYioIlkb/C6M6ObHGSia0kwoZa6grD3CNUCa/c/dlFKO +E06qN72fsYihp0ghHkBaCxb+YfYpIAPIpfuuTSGkVYyjpY0a8EQ1JlzbJctQkX5r +sd9jfHsrZriAGCzdsL/diG8bUi9Yex/G0ip8GGEuHs5e2bJ6+7O/mPlL6SL/0tI= +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/jp.reseed.i2p2.no.crt b/contrib/certificates/ssl/jp.reseed.i2p2.no.crt new file mode 100644 index 00000000..1cb5abec --- /dev/null +++ b/contrib/certificates/ssl/jp.reseed.i2p2.no.crt @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFqTCCA5GgAwIBAgIJAPsJOCng4aEOMA0GCSqGSIb3DQEBBQUAMGsxCzAJBgNV +BAYTAk5PMQ0wCwYDVQQIDARPc2xvMQ4wDAYDVQQHDAVKYXBhbjEMMAoGA1UECgwD +STJQMRMwEQYDVQQLDApJMlAgUmVzZWVkMRowGAYDVQQDDBFqcC5yZXNlZWQuaTJw +Mi5ubzAeFw0xNDA2MjgyMDQ3MThaFw0yNDA2MjUyMDQ3MThaMGsxCzAJBgNVBAYT +Ak5PMQ0wCwYDVQQIDARPc2xvMQ4wDAYDVQQHDAVKYXBhbjEMMAoGA1UECgwDSTJQ +MRMwEQYDVQQLDApJMlAgUmVzZWVkMRowGAYDVQQDDBFqcC5yZXNlZWQuaTJwMi5u +bzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALlZBIbb4MHqLPpUy298 +PG5z7RFo4bO7CxW2LO8DgE93KNbdkZuYpt6KcAW/gkDfKCiXTxDjyqmzZeBeIbcS +ea96jFc/pTknkiiSm9NX4ATcyRwvKXn6DR/iOiofP3G/sEkxgIdv3BgEYsF5jPQY +KefG0Jvl612cIX+1jC3lRRePYPUZnWxIuokXglLApeyhNzTK/KHIsLzR+56ScltM +pwGlroTky5ekPx4ZnJCxI+qFXWcgqdoNixPUkOtceYm7u5gd1D+mQDuCB5zfB+Pw +Iy9BTARot9M3fMrcRRVfEIGWwN1+bRnZvr0A/sqYMUqGPiUVOMi/mzyqZVQ14CGy +0idRhUKdOb/HNSmcep0Jwp0cP+VD/nCNU4JLptTLdErpTJrmDn+zkuQPPSMTzTWg +Fh3ktRsJ5zKfrnrBGxeKbciZgRkVHyWpv3+0AgbD8C3HvDj4qpkIO6D2gf+TREyM +frDXN6luqkThQcUFv+huMaL3Iul2doYqw5YPAdel6/cCD12n/FoEj5UJ47O/77DA +ITYfKCFRKDh/Ew7Ih3bH66uNaUUp+a0Sd6fNXLmWWr7gcn5B5CvrXhjPPror+Xyz +EZVByPTTfU1BkMQuxv20GG65M9g9wtXrD79N8di2wOfr4EG5i6L9ZvNTThwgWGGd +9f745WCnPL/ulLT9Glnlfk01AgMBAAGjUDBOMB0GA1UdDgQWBBR5Ed38JID7+JwB +hpOLi1Xt1ORyoTAfBgNVHSMEGDAWgBR5Ed38JID7+JwBhpOLi1Xt1ORyoTAMBgNV +HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQBRT/ourx4xT0n/qHF1vy8Ii02v +Hg5lHmzmiVn/3/S4q+t4HrOF6MSjjvVzVNk6JIIYb3+hwGUO31OLNZX60JfSMW+C +ffPiaNDLm/xE4yt4B/QZZDs0kv0RMjGau6k2XJPGvxVNl6LhM6LLvzMEtOGzBr0J +Ai4ZU+WqHk3nnXYHbg7C7Iuu8CT8tBpkaeW/VEN82dcLEulHFxA5Ia6HlwqrgvIW +w77oaOhOh5LKkdS8uHx4OUP8Mv25H2cMBblUdubbeqREyOGRGTkVXfRekD8K95ol +PfT9PhnhUXKRaSwy0nRqvRMiwk/CyIJTbMMflDET1P785diSvtJP0fOhkev9Uprz +FvLsPUTvANUz+vd2KJiLuGbR/d/LaJm18vdWx13vKVO60TBnyFQDS4RZbeuNp73v +x5fPTmiiPZYZj13m2xyes7SXJqhVbms0F39soThpuYrjCaHXyFgqah27+9Ivmbhu +EefPgLmkOx3v0kSfXdJYdji/mrKxERmqT1L34U6M32tCoSbjO7lakAV2opisbHEw +EehCuI83cGp/m3z8yjMoWV8Z4VoB+qMzxzgrXc5C2lxYAT4JggAV2SGcY9MszETI +/S7y5UypV4rutyJvHFrlJZKtp2B7Xi8N8n2NG1WGppYh9UShbFhDaVIMQpjZokAg +MHk7ixe0rSbnHcNF8g== +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/netdb.i2p2.no.crt b/contrib/certificates/ssl/netdb.i2p2.no.crt new file mode 100644 index 00000000..2ab5a131 --- /dev/null +++ b/contrib/certificates/ssl/netdb.i2p2.no.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC0DCCAjmgAwIBAgIJANdBFbakbhhOMA0GCSqGSIb3DQEBBQUAMIGAMQswCQYD +VQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzEMMAoGA1UECgwD +STJQMQwwCgYDVQQLDANJMlAxFjAUBgNVBAMMDW5ldGRiLmkycDIubm8xHzAdBgkq +hkiG9w0BCQEWEG1lZWhAaTJwbWFpbC5vcmcwHhcNMTIxMDIzMDExMjIyWhcNMTkx +MDIyMDExMjIyWjCBgDELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNV +BAcMBE9zbG8xDDAKBgNVBAoMA0kyUDEMMAoGA1UECwwDSTJQMRYwFAYDVQQDDA1u +ZXRkYi5pMnAyLm5vMR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCDvmjTpff6/XpiNuqoa9ZEKMlyq1o +kas9fHwnZax/0QTM3xusSQQ9DzeVMSx1ueYxhTZ6VLmE1mTr0aIndzugxGK/g85H +Y+cUl3nw7+5gLPMCUrKAXqQokE3mYxSNY3AUeend7nmHvm9iciw4+Sa2+6ROvQQy +kD31CEN6/I04rwIDAQABo1AwTjAdBgNVHQ4EFgQUV83dJhEcLbfJ+uh+MDYNPdah +RoQwHwYDVR0jBBgwFoAUV83dJhEcLbfJ+uh+MDYNPdahRoQwDAYDVR0TBAUwAwEB +/zANBgkqhkiG9w0BAQUFAAOBgQBQQlJym7mUMUM2ryKu20z2PSUzFyq5U4rWHeo3 +elbNaTsFBwi+Ot/Lg/A5I4V8gywH1fBTG5bYKDUYvWohz1qIg66G57B1zT1zK9yh +Byz9go44M3y1/kXXSsJlY9llG9DDicr1y6LfldwZJ5zFAd3iiB8D8UadP5YLqb7v +wb1F1g== +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/reseed.i2p-projekt.de.crt b/contrib/certificates/ssl/reseed.i2p-projekt.de.crt new file mode 100644 index 00000000..75f43dd6 --- /dev/null +++ b/contrib/certificates/ssl/reseed.i2p-projekt.de.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID7TCCAtWgAwIBAgIJAOHakoadaLRiMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYD +VQQGEwJBVDEQMA4GA1UECAwHQXVzdHJpYTENMAsGA1UEBwwER3JhejEMMAoGA1UE +CgwDSTJQMQ8wDQYDVQQLDAZSZXNlZWQxHjAcBgNVBAMMFXJlc2VlZC5pMnAtcHJv +amVrdC5kZTEdMBsGCSqGSIb3DQEJARYOcmVzZWVkQGkycDIuZGUwHhcNMTQwNTEw +MTAxOTM3WhcNMjQwNTA3MTAxOTM3WjCBjDELMAkGA1UEBhMCQVQxEDAOBgNVBAgM +B0F1c3RyaWExDTALBgNVBAcMBEdyYXoxDDAKBgNVBAoMA0kyUDEPMA0GA1UECwwG +UmVzZWVkMR4wHAYDVQQDDBVyZXNlZWQuaTJwLXByb2pla3QuZGUxHTAbBgkqhkiG +9w0BCQEWDnJlc2VlZEBpMnAyLmRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA8t5igIeAUZVX9k/A2gudRWVfToIV4yvlxmnH9UTJ8DTkWfHGbY9MmW2+ +b0ZdvIZDcgg1nvcLEKqCDQnIp3wLGdM8fdVSXqxA1dLyHdk6IrGVqb60qpGENeIc +EHiUeB1g0KqP4kLcj2sNlo+Vupjnu7qS8v0/LfZ3fq2m4vtx8dYnvo+JIzGL9K0f +/DOil8QIcdTZupzMbXd6P936Blm/1RdbW/uKROOuuYE38NwYOUCq2/Nd+T86S5DD +9wQBjy0U+9nNayWf6BOSuP6m2mxx/pA1CvKRq7CzI0Gqjo2Msd+i0dTL2WIO2JDp +5uykZ0GabRW3UrMEuyrzzK6U2RZ1dQIDAQABo1AwTjAdBgNVHQ4EFgQUIejD2MMl +6PpcCernYd3ku3sEWfswHwYDVR0jBBgwFoAUIejD2MMl6PpcCernYd3ku3sEWfsw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAupUg3ZTBSE7iRebjcZ+y +zgnRaClmgrv8Mpa1/weTuXKhJZ65k6+G5mplI5hN/crKi/3b6oyfRrYhgdTdb0rD +2CbrhBkPGGlubhkjkxWjAhibzU6Kt3a7WOjykGnslpCZhwS/hiVB7ZE2JGdphFld +aJTKt12CytyP3GyIQyyX7O2t92dk8cW4tlxRVpaPNr59lk0V50qpvNmNyhxv3yDz +taop/etfjHStq1YrltHWH0d4Dxy8ubb7nV19uvPcE0+MrR2xm7jvOBfGjAf1bQ7Z +rk7RMHio4xWFJZO7TSzL5/8EH2jX6ZqpH+hZ6sV8TmzuRWsPkm0doXWr+HBZ/gMt +5w== +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/reseed.info.crt b/contrib/certificates/ssl/reseed.info.crt new file mode 100644 index 00000000..83d1a33e --- /dev/null +++ b/contrib/certificates/ssl/reseed.info.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDRDCCAiwCCQDCm/Zrmali9zANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJB +VTETMBEGA1UECBMKU29tZS1TdGF0ZTELMAkGA1UEBxMCSEgxDDAKBgNVBAoTA0ky +UDEPMA0GA1UECxMGcmVzZWVkMRQwEgYDVQQDEwtyZXNlZWQuaW5mbzAeFw0xMjEw +MjcxODU3NDNaFw0xNjEyMDUxODU3NDNaMGQxCzAJBgNVBAYTAkFVMRMwEQYDVQQI +EwpTb21lLVN0YXRlMQswCQYDVQQHEwJISDEMMAoGA1UEChMDSTJQMQ8wDQYDVQQL +EwZyZXNlZWQxFDASBgNVBAMTC3Jlc2VlZC5pbmZvMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAt9nz0iUvjdX4Hkhfk0FbBOeEP4i/FG3V4VrEdQfcviSF +XgzGYeRtGsvrFWP/5+6bcGnOkIy/jrKJfij3AjKJh8gTzqiNNNnV8VcHwFSNp+hZ +D4BM+UHPACV1Pjd3HQe6f0+LvcTs3HQgIkNkwUyqRuXOm/5Mk6SWSu1740aSwHCj +Kk0x1FByzI0YBvXCPX6TVk6sJqKkQyLzK0CSGSeqUq8GvGCq+jT9k62Su7ooxCwi +GzxaFjMdVYxuI8cuT5Cni+SUw1Ia8vhESnIy6slwzk37xNI80VuMvRT6rD2KcXDH +mK7ml1qL0rJWoF5AE+x/nen4V41mouv1W9rk3wTlTQIDAQABMA0GCSqGSIb3DQEB +BQUAA4IBAQAr6RBviBDW4bnPDTcdtstTDdaYX9yzoh+zzeGB0dUR26GKoOjpSItb +B9nrsW1eJ2wbblfGBUoXhcmNByKHXXHejMhmurHjdei2BuLbTsknN8DPKXu5UF9z +cg4cKQkxgzXOcNYlaF4+sfwFXDHJ4we/8vduVgkyo8R66543/Sh/nIMvq2slRT4w +wIBOVcMb2XxlbdwHW9XALAz9sto+4GH9GAC24f8ngluOpHijMnOOIo4dHibQ5hM9 +KcDpHezP0ugMTAxS2NmtVahwAqa2IjpqR7aEQ2wLvxQzDqrXo93L93+b2FKRUQXH +Duud/n/w0kVV3DaIGikOsJayoanR+9HD +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/uk.reseed.i2p2.no.crt b/contrib/certificates/ssl/uk.reseed.i2p2.no.crt new file mode 100644 index 00000000..84f3f073 --- /dev/null +++ b/contrib/certificates/ssl/uk.reseed.i2p2.no.crt @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFsTCCA5mgAwIBAgIJANgzPow6thRuMA0GCSqGSIb3DQEBBQUAMG8xCzAJBgNV +BAYTAk5PMQ0wCwYDVQQIDARPc2xvMQswCQYDVQQHDAJVSzETMBEGA1UECgwKSTJQ +IFJlc2VlZDETMBEGA1UECwwKSTJQIFJlc2VlZDEaMBgGA1UEAwwRdWsucmVzZWVk +LmkycDIubm8wHhcNMTQwNjI4MjA0OTA3WhcNMjQwNjI1MjA0OTA3WjBvMQswCQYD +VQQGEwJOTzENMAsGA1UECAwET3NsbzELMAkGA1UEBwwCVUsxEzARBgNVBAoMCkky +UCBSZXNlZWQxEzARBgNVBAsMCkkyUCBSZXNlZWQxGjAYBgNVBAMMEXVrLnJlc2Vl +ZC5pMnAyLm5vMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxlVlXWn5 +Ham6ZqM6FkH6ZoXeXbncY/PnF669mCPcrPH56V2xZXwpeCXHWfu7YiHuhXXZSmzP +zwRrawHZTJulHt4e6j27JnDuEj69gmFpyi4B1djQ0kav0aJeagwCPG2do/UD7Cbr +4nITkU4CifLe47IUW/2K/EBI6bZGsRIDHJ3A+fAQmLnvehEkpvLN+cvtkpJOtZYx +6WvbwLsirkISnaio4//UY8M4poIu9mSG5pvNLagn9uoRPUSuj8jDEysB1Nmh12Zu +gFnt2XcxQB9/0krB5GnDTodrgfsz/UPbk44l4kFmQoLv5ACFndH69RKftogisauj +VVUrqCL3l9TcNsx8GLqZkeWhCwdZycZFjBhK01zihTYPEiU2HXfCNWhzLqxrM2Hh +r1ci+56fyNdn/ssO4o3hrGaWPDiayiHlEGEJxaG/ueKX2c3c0UJKkIGBPTEcdBjW +q42n/7EhY/ISaieQXPRK+gVm18I1OlGUH5FEYELO20bL88J8pr/bYuJyJnC8fiMP +YzKZuiVhey6dPr0zZgNDHyRbOlZqQllzKd1wbzbE4xqdUZfBWYwtRpdOJKDw4eoi +M69TwPQFfudeiudnMcR1gN37OkxS7UTEdsYIB5urgLb6qQD+tYFsxpcVPkedJw62 +3TobhZjucaEZWzePd4u9faT9mQBXBAgY6VcCAwEAAaNQME4wHQYDVR0OBBYEFDTN +QRqhzaLc6XX2gFg26K//e0+8MB8GA1UdIwQYMBaAFDTNQRqhzaLc6XX2gFg26K// +e0+8MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggIBACcJ99Z45ghglvL3 +/yMnx6IkOSneEm2/ADQoOabBQSC2grRAMBescKUiqpgbpBFalIPbPJUVrlH9tXYB +izNhqWETBY2tNy7AEHcJcCsAFuC2gOhaFH7FLgPA8V5IJmZ+McjB8REyowcN+CP4 +GDY8s5/yr9S3HpKLD80UV18UX/j5m4b6I1w61QceMOSt6ahTtlnyvNBonFW94L1c +RmkdbhxYWn2eeUas62Q/+9bjr24E0weDKqopa3bbO7MWJ3mKkS4rua42j8GG3Q3q +UWPGh4zm+2+Ncjmz0Ho73RyYDDcp9IjwlAEv+NW86rz/5Pdkhoy+SzQwFYAwNgaQ +FRKb6ltpslxmu3tUdZ7Ydrj6MBGQyH2gRVm9qByro7WGI4UsyzsjP009Iu6dbhdC +2ddTGMisXF3dOmdRWh8dlggmW6gV4iaVgZkzLtrc9S0SK66utKMVXa4EUTm6XogX +F5ImPnVzIMo2qF2pP31aGDzKqJF3GNjGj+xHRVau5whz0a4ESY6V14PLTEL4Vc/H +J9uLCySifvqN+jzs5iY2QvNXjg2zPaTJbnjxxpYQJVSQHX6SyRcszhChqQzxnbyo ++S19BRclqzufRq6pp6VcOiID0BB7qPcrUHM9h1ingMXcZZlGBgHew9cY7tb5TAox +o+aTNc4k/7E543FVbs40dpOD2Fcr +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/us.reseed.i2p2.no.crt b/contrib/certificates/ssl/us.reseed.i2p2.no.crt new file mode 100644 index 00000000..eae724e9 --- /dev/null +++ b/contrib/certificates/ssl/us.reseed.i2p2.no.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDUDCCAjgCCQCkTcCJMdZV7zANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJO +TzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzENMAsGA1UECgwET3NsbzES +MBAGA1UECwwJTm9yZGNsb3VkMRowGAYDVQQDDBF1cy5yZXNlZWQuaTJwMi5ubzAe +Fw0xNDA2MjcyMjQxMjFaFw0yNDA2MjQyMjQxMjFaMGoxCzAJBgNVBAYTAk5PMQ0w +CwYDVQQIDARPc2xvMQ0wCwYDVQQHDARPc2xvMQ0wCwYDVQQKDARPc2xvMRIwEAYD +VQQLDAlOb3JkY2xvdWQxGjAYBgNVBAMMEXVzLnJlc2VlZC5pMnAyLm5vMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomVoBEc53jzy3xGMfgRaKyX6MaGG +KAmwu0uMTX6bVzGjy56JMMq3luoxOrpvgrNZF52lu7i36Tejo0HM75AHoea1es55 +DNLmrlDeqzlBU2WibOnizbB8G+tlMEbx8eAGAWk/Wv/vH8CAKmxjImslmbajzZC2 +LEH7inp3J5T2sVV7zmXeL9OEPKNyohbu6Mrno2IAlEOr8cu+lWAaFWzpknnR1gBX +NkB/8+7vK5Fq4MT7B0qnXPxmaWDbUOepPPni8u+2L9+qt19vZH4/6KNuH7xd7JLz +FfIdol6jy2cBQyAK7cVKWDHNk7ceB4Dl0mjBDbBIRTtLK+rfdnVmfWn8aQIDAQAB +MA0GCSqGSIb3DQEBBQUAA4IBAQCQH4QJMp5xneh2ah7fiuVdtKbiv6QNunRz7nb/ +mWYyqmBX7EHL8jOG5qmPELDgDt58HmnaYMo05nEJb9JhAoviEDXSYw0s6eN4n4nc +MKqgR/HLLSiXPwT+Wi1MI57OYim5AFTUCYTSaWFUT+dZKYb0QPE1XjGpQXi3ppsJ +3TJG71tOzJmZT6vRPmdTHJO70v6ZEhr5w4SiGx07gNmcgO8WRyb5ajOwSHiGKrj6 +UsuRNhtCyZaAEmelR9mfKBR1J2Nb+9jTz6mJtpT82WY3bst6mFk+A+mMWBQy7Hjt +gpdSDBCcFx9if+AKINGLgFvFKV2q8UzbfXms19NsVt9Hu7W3 +-----END CERTIFICATE----- diff --git a/contrib/certificates/ssl/www.cacert.org.crt b/contrib/certificates/ssl/www.cacert.org.crt new file mode 100644 index 00000000..e7dfc829 --- /dev/null +++ b/contrib/certificates/ssl/www.cacert.org.crt @@ -0,0 +1,41 @@ +-----BEGIN CERTIFICATE----- +MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 +IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB +IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA +Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO +BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi +MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ +ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ +8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 +zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y +fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 +w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc +G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k +epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q +laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ +QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU +fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 +YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w +ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY +gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe +MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 +IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy +dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw +czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 +dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl +aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC +AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg +b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB +ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc +nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg +18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c +gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl +Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY +sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T +SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF +CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum +GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk +zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW +omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD +-----END CERTIFICATE----- diff --git a/filelist.mk b/filelist.mk new file mode 100644 index 00000000..4ebf7c09 --- /dev/null +++ b/filelist.mk @@ -0,0 +1,18 @@ + + +CPP_FILES := CryptoConst.cpp base64.cpp NTCPSession.cpp RouterInfo.cpp Transports.cpp \ + RouterContext.cpp NetDb.cpp LeaseSet.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelGateway.cpp \ + TransitTunnel.cpp I2NPProtocol.cpp Log.cpp Garlic.cpp HTTPServer.cpp Streaming.cpp Identity.cpp \ + SSU.cpp util.cpp Reseed.cpp DaemonLinux.cpp SSUData.cpp i2p.cpp aes.cpp SOCKS.cpp UPnP.cpp \ + TunnelPool.cpp HTTPProxy.cpp AddressBook.cpp Daemon.cpp + + +H_FILES := CryptoConst.h base64.h NTCPSession.h RouterInfo.h Transports.h \ + RouterContext.h NetDb.h LeaseSet.h Tunnel.h TunnelEndpoint.h TunnelGateway.h \ + TransitTunnel.h I2NPProtocol.h Log.h Garlic.h HTTPServer.h Streaming.h Identity.h \ + SSU.h util.h Reseed.h DaemonLinux.h SSUData.h i2p.h aes.h SOCKS.h UPnP.h TunnelPool.h \ + HTTPProxy.h AddressBook.h Daemon.h + + +OBJECTS = $(addprefix obj/, $(notdir $(CPP_FILES:.cpp=.o))) + diff --git a/i2p.cpp b/i2p.cpp index 2bd2b5b8..89966328 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -5,11 +5,13 @@ int main( int argc, char* argv[] ) { Daemon.init(argc, argv); - Daemon.start(); - while (Daemon.running) + if (Daemon.start()) { - //TODO Meeh: Find something better to do here. - std::this_thread::sleep_for (std::chrono::seconds(1)); + while (Daemon.running) + { + //TODO Meeh: Find something better to do here. + std::this_thread::sleep_for (std::chrono::seconds(1)); + } } Daemon.stop(); return EXIT_SUCCESS;