From a4c25e773cfa9afcde1f2c0700f330c94d8cdedf Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 25 Jan 2014 21:47:01 -0500 Subject: [PATCH 01/46] check for transport protocols compatibility between routers --- NetDb.cpp | 30 ++++++++++++++++++++---------- NetDb.h | 2 +- RouterInfo.cpp | 32 +++++++++++++++++--------------- RouterInfo.h | 11 +++++++++++ Tunnel.cpp | 9 +++++---- Tunnel.h | 3 ++- 6 files changed, 56 insertions(+), 31 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 75669260..4a460d8f 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -427,7 +427,7 @@ namespace data auto inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); if (outbound && inbound) { - auto floodfill = GetRandomNTCPRouter (true); + auto floodfill = GetRandomRouter (outbound->GetEndpointRouter (), true); if (floodfill) { LogPrint ("Exploring new routers ..."); @@ -495,19 +495,29 @@ namespace data return last; } - const RouterInfo * NetDb::GetRandomRouter () const + const RouterInfo * NetDb::GetRandomRouter (const RouterInfo * compatibleWith, bool floodfillOnly) const { CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1), i = 0; - RouterInfo * last = nullptr; - for (auto it: m_RouterInfos) + uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1); + for (int j = 0; j < 2; j++) { - if (!it.second->IsUnreachable ()) - last = it.second; - if (i >= ind) break; - else i++; + uint32_t i = 0; + for (auto it: m_RouterInfos) + { + if (i >= ind) + { + if (!it.second->IsUnreachable () && + (!compatibleWith || it.second->IsCompatible (*compatibleWith)) && + (!floodfillOnly || it.second->IsFloodfill ())) + return it.second; + } + else + i++; + } + // we couldn't find anything, try second pass + ind = 0; } - return last; + return nullptr; // seem we have too few routers } void NetDb::PostI2NPMsg (I2NPMessage * msg) diff --git a/NetDb.h b/NetDb.h index 03be5ed6..7f56c169 100644 --- a/NetDb.h +++ b/NetDb.h @@ -68,7 +68,7 @@ namespace data void HandleDatabaseSearchReplyMsg (I2NPMessage * msg); const RouterInfo * GetRandomNTCPRouter (bool floodfillOnly = false) const; - const RouterInfo * GetRandomRouter () const; + const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith = nullptr, bool floodfillOnly = false) const; void PostI2NPMsg (I2NPMessage * msg); diff --git a/RouterInfo.cpp b/RouterInfo.cpp index ee9a60c2..8126d622 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -13,19 +13,18 @@ #include "RouterContext.h" - namespace i2p { namespace data { RouterInfo::RouterInfo (const char * filename): - m_IsUpdated (false), m_IsUnreachable (false) + m_IsUpdated (false), m_IsUnreachable (false), m_SupportedTransports (0) { ReadFromFile (filename); } RouterInfo::RouterInfo (const uint8_t * buf, int len): - m_IsUpdated (true) + m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0) { memcpy (m_Buffer, buf, len); m_BufferLen = len; @@ -111,7 +110,15 @@ namespace data // TODO: we should try to resolve address here LogPrint ("Unexpected address ", value); SetUnreachable (true); - } + } + else + { + // add supported protocol + if (address.host.is_v4 ()) + m_SupportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4; + else + m_SupportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6; + } } else if (!strcmp (key, "port")) address.port = boost::lexical_cast(value); @@ -275,17 +282,12 @@ namespace data bool RouterInfo::IsNTCP (bool v4only) const { - for (auto& address : m_Addresses) - { - if (address.transportStyle == eTransportNTCP) - { - if (!v4only || address.host.is_v4 ()) - return true; - } - } - return false; - } - + if (v4only) + return m_SupportedTransports & eNTCPV4; + else + return m_SupportedTransports & (eNTCPV4 | eNTCPV6); + } + RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) { for (auto& address : m_Addresses) diff --git a/RouterInfo.h b/RouterInfo.h index 44dae3f1..76ebf7cf 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -17,6 +17,14 @@ namespace data { public: + enum SupportedTranports + { + eNTCPV4 = 0x01, + eNTCPV6 = 0x20, + eSSUV4 = 0x40, + eSSUV6 = 0x80 + }; + enum TransportStyle { eTransportUnknown = 0, @@ -53,6 +61,8 @@ namespace data const char * GetProperty (const char * key) const; bool IsFloodfill () const; bool IsNTCP (bool v4only = true) const; + bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; + void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; bool IsUnreachable () const { return m_IsUnreachable; }; @@ -91,6 +101,7 @@ namespace data std::vector
m_Addresses; std::map m_Properties; bool m_IsUpdated, m_IsUnreachable; + uint8_t m_SupportedTransports; }; } } diff --git a/Tunnel.cpp b/Tunnel.cpp index fe904369..1163f47e 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -397,11 +397,12 @@ namespace tunnel { LogPrint ("Creating two hops outbound tunnel..."); + auto firstHop = i2p::data::netdb.GetRandomNTCPRouter (); // first hop must be NTCP CreateTunnel ( new TunnelConfig (std::vector { - i2p::data::netdb.GetRandomNTCPRouter (), // first hop must be NTCP - i2p::data::netdb.GetRandomRouter () + firstHop, + i2p::data::netdb.GetRandomRouter (firstHop) }, inboundTunnel->GetTunnelConfig ())); } @@ -449,8 +450,8 @@ namespace tunnel CreateTunnel ( new TunnelConfig (std::vector { - i2p::data::netdb.GetRandomNTCPRouter (), - router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomNTCPRouter () + i2p::data::netdb.GetRandomRouter (outboundTunnel->GetEndpointRouter ()), + router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomNTCPRouter () // last hop must be NTCP }), outboundTunnel); } diff --git a/Tunnel.h b/Tunnel.h index a189da0d..3498eae3 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -67,7 +67,8 @@ namespace tunnel void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); void SendTunnelDataMsg (std::vector msgs); // multiple messages - + const i2p::data::RouterInfo * GetEndpointRouter () const + { return GetTunnelConfig ()->GetLastHop ()->router; }; size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }; // implements TunnelBase From bb2fcbf668d475fdc3418b2ef80da399d3c7de17 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 26 Jan 2014 09:06:06 -0500 Subject: [PATCH 02/46] print out message type sent to an inbound tunnel --- I2NPProtocol.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 502a2e40..6503d70f 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -386,15 +386,13 @@ namespace i2p TunnelGatewayHeader * header = (TunnelGatewayHeader *)msg->GetPayload (); uint32_t tunnelID = be32toh(header->tunnelID); uint16_t len = be16toh(header->length); - LogPrint ("TunnelGateway of ", (int)len, " bytes for tunnel ", (unsigned int)tunnelID); + // we make payload as new I2NP message to send + msg->offset += sizeof (I2NPHeader) + sizeof (TunnelGatewayHeader); + msg->len = msg->offset + len; + LogPrint ("TunnelGateway of ", (int)len, " bytes for tunnel ", (unsigned int)tunnelID, ". Msg type ", (int)msg->GetHeader()->typeID); i2p::tunnel::TransitTunnel * tunnel = i2p::tunnel::tunnels.GetTransitTunnel (tunnelID); if (tunnel) - { - // we make payload as new I2NP message to send - msg->offset += sizeof (I2NPHeader) + sizeof (TunnelGatewayHeader); - msg->len = msg->offset + len; tunnel->SendTunnelDataMsg (nullptr, 0, msg); - } else { LogPrint ("Tunnel ", (unsigned int)tunnelID, " not found"); From f763fd3268f4b9fe82b98bfca7ff42fbd3e48d3a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 26 Jan 2014 09:07:31 -0500 Subject: [PATCH 03/46] request lease's gateway if not found in the netDb --- LeaseSet.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/LeaseSet.cpp b/LeaseSet.cpp index efa6409f..2b75b463 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -3,6 +3,7 @@ #include "CryptoConst.h" #include "Log.h" #include "Timestamp.h" +#include "NetDb.h" #include "LeaseSet.h" namespace i2p @@ -28,6 +29,7 @@ namespace data memcpy (m_EncryptionKey, header->encryptionKey, 256); LogPrint ("LeaseSet num=", (int)header->num); + // process leases const uint8_t * leases = buf + sizeof (H); for (int i = 0; i < header->num; i++) { @@ -36,8 +38,16 @@ namespace data lease.endDate = be64toh (lease.endDate); m_Leases.push_back (lease); leases += sizeof (Lease); - } + // check if lease's gateway is in our netDb + if (!netdb.FindRouter (lease.tunnelGateway)) + { + // if not found request it + LogPrint ("Lease's tunnel gateway not found. Requested"); + netdb.RequestDestination (lease.tunnelGateway); + } + } + // verify CryptoPP::DSA::PublicKey pubKey; pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, From ae51b11ced78e7f48d76dab3980bcacfbd8c4e9e Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 26 Jan 2014 15:24:21 -0500 Subject: [PATCH 04/46] request RouterInfo connecting directly to a floodfill --- NetDb.cpp | 91 ++++++++++++++++++++++++++++++++++--------------------- NetDb.h | 4 ++- 2 files changed, 60 insertions(+), 35 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 4a460d8f..38814549 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -9,6 +9,7 @@ #include "Timestamp.h" #include "I2NPProtocol.h" #include "Tunnel.h" +#include "Transports.h" #include "RouterContext.h" #include "Garlic.h" #include "NetDb.h" @@ -30,6 +31,16 @@ namespace data m_LastReplyTunnel = replyTunnel; return msg; } + + I2NPMessage * RequestedDestination::CreateRequestMessage (const IdentHash& floodfill) + { + I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination, + i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); + m_ExcludedPeers.insert (floodfill); + m_LastRouter = nullptr; + m_LastReplyTunnel = nullptr; + return msg; + } NetDb netdb; @@ -252,44 +263,49 @@ namespace data void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet) { - i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); - if (outbound) - { - i2p::tunnel::InboundTunnel * inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); - if (inbound) + if (isLeaseSet) // we request LeaseSet through tunnels + { + i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); + if (outbound) { - RequestedDestination * dest = CreateRequestedDestination (destination, isLeaseSet); - auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ()); - if (floodfill) - { - std::vector msgs; - // our RouterInfo - msgs.push_back (i2p::tunnel::TunnelMessageBlock - { - i2p::tunnel::eDeliveryTypeRouter, - floodfill->GetIdentHash (), 0, - CreateDatabaseStoreMsg () - }); - - // DatabaseLookup message - dest->SetLastOutboundTunnel (outbound); - msgs.push_back (i2p::tunnel::TunnelMessageBlock - { - i2p::tunnel::eDeliveryTypeRouter, - floodfill->GetIdentHash (), 0, - dest->CreateRequestMessage (floodfill, inbound) - }); + i2p::tunnel::InboundTunnel * inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); + if (inbound) + { + RequestedDestination * dest = CreateRequestedDestination (destination, isLeaseSet); + auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ()); + if (floodfill) + { + std::vector msgs; + // DatabaseLookup message + dest->SetLastOutboundTunnel (outbound); + msgs.push_back (i2p::tunnel::TunnelMessageBlock + { + i2p::tunnel::eDeliveryTypeRouter, + floodfill->GetIdentHash (), 0, + dest->CreateRequestMessage (floodfill, inbound) + }); - outbound->SendTunnelDataMsg (msgs); + outbound->SendTunnelDataMsg (msgs); + } + else + LogPrint ("No more floodfills found"); } else - LogPrint ("No more floodfills found"); - } + LogPrint ("No inbound tunnels found"); + } else - LogPrint ("No inbound tunnels found"); - } - else - LogPrint ("No outbound tunnels found"); + LogPrint ("No outbound tunnels found"); + } + else // RouterInfo is requested directly + { + RequestedDestination * dest = CreateRequestedDestination (destination, false); + auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ()); + if (floodfill) + { + dest->SetLastOutboundTunnel (nullptr); + i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); + } + } } void NetDb::HandleDatabaseStoreMsg (uint8_t * buf, size_t len) @@ -402,11 +418,18 @@ namespace data dest->GetLastRouter ()->GetIdentHash (), 0, msg }); } + } + else // we should send directly + { + if (!dest->IsLeaseSet ()) // if not LeaseSet + i2p::transports.SendMessage (router, dest->CreateRequestMessage (router)); + else + LogPrint ("Can't request LeaseSet"); } } } - if (msgs.size () > 0) + if (outbound && msgs.size () > 0) outbound->SendTunnelDataMsg (msgs); } else diff --git a/NetDb.h b/NetDb.h index 7f56c169..7baebc5d 100644 --- a/NetDb.h +++ b/NetDb.h @@ -30,9 +30,11 @@ namespace data const RouterInfo * GetLastRouter () const { return m_LastRouter; }; const i2p::tunnel::InboundTunnel * GetLastReplyTunnel () const { return m_LastReplyTunnel; }; bool IsExploratory () const { return m_IsExploratory; }; + bool IsLeaseSet () const { return m_IsLeaseSet; }; bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); }; I2NPMessage * CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel); - + I2NPMessage * CreateRequestMessage (const IdentHash& floodfill); + i2p::tunnel::OutboundTunnel * GetLastOutboundTunnel () const { return m_LastOutboundTunnel; }; void SetLastOutboundTunnel (i2p::tunnel::OutboundTunnel * tunnel) { m_LastOutboundTunnel = tunnel; }; From 27426a60237223d187003db711a810e3bc6d9b3f Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 26 Jan 2014 18:22:30 -0500 Subject: [PATCH 05/46] save out-of-seq messages and process them later --- Streaming.cpp | 33 ++++++++++++++++++++++++++++++--- Streaming.h | 15 +++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/Streaming.cpp b/Streaming.cpp index 99d51618..1a848c28 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -1,4 +1,3 @@ -#include "I2PEndian.h" #include #include #include @@ -26,6 +25,8 @@ namespace stream { while (auto packet = m_ReceiveQueue.Get ()) delete packet; + for (auto it: m_SavedPackets) + delete it; } void Stream::HandleNextPacket (Packet * packet) @@ -80,6 +81,26 @@ namespace stream m_LastReceivedSequenceNumber = receivedSeqn; SendQuickAck (); + + // we should also try stored messages if any + for (auto it = m_SavedPackets.begin (); it != m_SavedPackets.end ();) + { + if ((*it)->GetReceivedSeqn () == m_LastReceivedSequenceNumber + 1) + { + Packet * packet = *it; + m_SavedPackets.erase (it++); + + LogPrint ("Process saved packet seqn=", packet->GetReceivedSeqn ()); + if (packet->GetLength () > 0) + m_ReceiveQueue.Put (packet); + else + delete packet; + m_LastReceivedSequenceNumber++; + SendQuickAck (); + } + else + break; + } } else { @@ -90,13 +111,14 @@ namespace stream m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); // pick another tunnel if (m_OutboundTunnel) SendQuickAck (); // resend ack for previous message again + delete packet; // packet dropped } else { LogPrint ("Missing messages from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1); - // actually do nothing. just wait for missing message again + // save message and wait for missing message again + SavePacket (packet); } - delete packet; // packet dropped } if (flags & PACKET_FLAG_CLOSE) @@ -107,6 +129,11 @@ namespace stream } } + void Stream::SavePacket (Packet * packet) + { + m_SavedPackets.insert (packet); + } + size_t Stream::Send (uint8_t * buf, size_t len, int timeout) { if (!m_IsOpen) diff --git a/Streaming.h b/Streaming.h index cc772190..248d8ee2 100644 --- a/Streaming.h +++ b/Streaming.h @@ -3,7 +3,9 @@ #include #include +#include #include +#include "I2PEndian.h" #include "Queue.h" #include "Identity.h" #include "LeaseSet.h" @@ -37,6 +39,16 @@ namespace stream Packet (): len (0), offset (0) {}; uint8_t * GetBuffer () { return buf + offset; }; size_t GetLength () const { return len - offset; }; + + uint32_t GetReceivedSeqn () const { return be32toh (*(uint32_t *)(buf + 8)); }; + }; + + struct PacketCmp + { + bool operator() (const Packet * p1, const Packet * p2) const + { + return p1->GetReceivedSeqn () < p2->GetReceivedSeqn (); + }; }; class StreamingDestination; @@ -61,6 +73,8 @@ namespace stream void ConnectAndSend (uint8_t * buf, size_t len); void SendQuickAck (); + + void SavePacket (Packet * packet); private: @@ -69,6 +83,7 @@ namespace stream StreamingDestination * m_LocalDestination; const i2p::data::LeaseSet * m_RemoteLeaseSet; i2p::util::Queue m_ReceiveQueue; + std::set m_SavedPackets; i2p::tunnel::OutboundTunnel * m_OutboundTunnel; }; From 8d4b98c83ae541ac8c8ce29d44e9cadd4c3e02ee Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 27 Jan 2014 16:52:17 -0500 Subject: [PATCH 06/46] SSUHeader and authenticate added --- SSU.cpp | 10 ++++++++++ SSU.h | 20 +++++++++++++++++++- hmac.h | 3 +-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index aebab995..e77ccb66 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -14,6 +14,16 @@ namespace ssu void SSUSession::ProcessNextMessage (uint8_t * buf, std::size_t len) { + switch (m_State) + { + default: + LogPrint ("SSU state not implemented yet"); + } + } + + void SSUSession::Authenticate (uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey) + { + m_Encryption.SetKeyWithIV (aesKey, 32, iv); } SSUServer::SSUServer (boost::asio::io_service& service, int port): diff --git a/SSU.h b/SSU.h index 8bb2c6fa..073184f3 100644 --- a/SSU.h +++ b/SSU.h @@ -4,11 +4,24 @@ #include #include #include +#include +#include +#include "I2PEndian.h" namespace i2p { namespace ssu { +#pragma pack(1) + struct SSUHeader + { + uint8_t mac[16]; + uint8_t iv[16]; + uint8_t flag; + uint32_t time; + }; +#pragma pack() + const int SSU_MTU = 1484; // payload types (4 bits) @@ -38,11 +51,16 @@ namespace ssu public: SSUSession (); - void ProcessNextMessage (uint8_t * buf, std::size_t len); + void ProcessNextMessage (uint8_t * buf, size_t len); + + private: + + void Authenticate (uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); private: SessionState m_State; + CryptoPP::CBC_Mode::Encryption m_Encryption; }; class SSUServer diff --git a/hmac.h b/hmac.h index 7b77af28..df35a142 100644 --- a/hmac.h +++ b/hmac.h @@ -19,7 +19,7 @@ namespace crypto // block size is 64 bytes { size_t totalLen = len + 64 + 32; - uint8_t * buf = new uint8_t[totalLen]; // TODO: reuse buffers + uint8_t buf[2048]; // ikeypad ((uint64_t *)buf)[0] = ((uint64_t *)key)[0] ^ IPAD; ((uint64_t *)buf)[1] = ((uint64_t *)key)[1] ^ IPAD; @@ -51,7 +51,6 @@ namespace crypto // calculate digest CryptoPP::Weak1::MD5().CalculateDigest (digest, buf, totalLen); - delete[] buf; } } } From 72fed33930928dfd9cb943e943b7e6bdc90a571e Mon Sep 17 00:00:00 2001 From: Meeh Date: Tue, 28 Jan 2014 01:13:35 +0100 Subject: [PATCH 07/46] Adding missing pthread library to linker. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 84c7a32f..ebe266b8 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ OBJECTS = i2p.o base64.o NTCPSession.o RouterInfo.o Transports.o RouterContext.o NetDb.o LeaseSet.o Tunnel.o TunnelEndpoint.o TunnelGateway.o TransitTunnel.o \ I2NPProtocol.o Log.o Garlic.o HTTPServer.o Streaming.o Identity.o SSU.o INCFLAGS = -LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem +LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lpthread LIBS = all: i2p From 3016c42e2e93c314761a809244526b3c1d13f1b0 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 27 Jan 2014 19:48:46 -0500 Subject: [PATCH 08/46] read intro key for SSU address --- RouterInfo.cpp | 14 +++++++++++++- RouterInfo.h | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 8126d622..44bd90e4 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -122,6 +122,8 @@ namespace data } else if (!strcmp (key, "port")) address.port = boost::lexical_cast(value); + else if (!strcmp (key, "key")) + Base64ToByteStream (value, strlen (value), address.key, 32); } m_Addresses.push_back(address); } @@ -289,10 +291,20 @@ namespace data } RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) + { + return GetAddress (eTransportNTCP, v4only); + } + + RouterInfo::Address * RouterInfo::GetSSUAddress (bool v4only) + { + return GetAddress (eTransportSSU, v4only); + } + + RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only) { for (auto& address : m_Addresses) { - if (address.transportStyle == eTransportNTCP) + if (address.transportStyle == s) { if (!v4only || address.host.is_v4 ()) return &address; diff --git a/RouterInfo.h b/RouterInfo.h index 76ebf7cf..d7fc6dd9 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -39,6 +39,7 @@ namespace data int port; uint64_t date; uint8_t cost; + uint8_t key[32]; // into key for SSU }; RouterInfo (const char * filename); @@ -54,6 +55,7 @@ namespace data uint64_t GetTimestamp () const { return m_Timestamp; }; const std::vector
& GetAddresses () const { return m_Addresses; }; Address * GetNTCPAddress (bool v4only = true); + Address * GetSSUAddress (bool v4only = true); const RoutingKey& GetRoutingKey () const { return m_RoutingKey; }; void AddNTCPAddress (const char * host, int port); @@ -88,6 +90,7 @@ namespace data size_t ReadString (char * str, std::istream& s); void WriteString (const std::string& str, std::ostream& s); void UpdateIdentHashBase64 (); + Address * GetAddress (TransportStyle s, bool v4only); private: From ca47d1552be8d8d03aeec530bdc197378a409819 Mon Sep 17 00:00:00 2001 From: Meeh Date: Tue, 28 Jan 2014 02:54:50 +0100 Subject: [PATCH 09/46] Updating gitignore --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index b9d6bd92..3c69f891 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +# i2pd +*.o +router.info +router.keys + ################# ## Eclipse ################# From 58386bb88e5d38fed70e645616125899c5c7b959 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 28 Jan 2014 16:49:54 -0500 Subject: [PATCH 10/46] Encrypt/Decrypt/Validate SSU packet --- SSU.cpp | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- SSU.h | 25 +++++++++--- 2 files changed, 130 insertions(+), 11 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index e77ccb66..5cb7cfe5 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -1,5 +1,7 @@ +#include #include #include "Log.h" +#include "RouterContext.h" #include "hmac.h" #include "SSU.h" @@ -8,22 +10,94 @@ namespace i2p namespace ssu { - SSUSession::SSUSession (): m_State (eSessionStateUnknown) + SSUSession::SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint, + i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint), + m_State (eSessionStateUnknown) { } - void SSUSession::ProcessNextMessage (uint8_t * buf, std::size_t len) + void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len) { switch (m_State) { + case eSessionStateUnknown: + // we assume session request + ProcessSessionRequest (buf, len); + break; default: LogPrint ("SSU state not implemented yet"); } } - void SSUSession::Authenticate (uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey) + void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len) + { + auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); + if (address) + { + // use intro key for verification and decryption + if (Validate (buf, len, address->key)) + { + m_State = eSessionStateRequestReceived; + LogPrint ("Session request received"); + Decrypt (buf, len, address->key); + // TODO: + } + else + LogPrint ("MAC verifcation failed"); + } + else + LogPrint ("SSU is not supported"); + } + + void SSUSession::Encrypt (uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey) { + if (len < sizeof (SSUHeader)) + { + LogPrint ("Unexpected SSU packet length ", len); + return; + } + SSUHeader * header = (SSUHeader *)buf; + memcpy (header->iv, iv, 16); + uint8_t * encrypted = &header->flag; + uint16_t encryptedLen = len - (encrypted - buf); m_Encryption.SetKeyWithIV (aesKey, 32, iv); + m_Encryption.ProcessData (encrypted, encrypted, encryptedLen); + // assume actual buffer size is 18 (16 + 2) bytes more + memcpy (buf + len, iv, 16); + *(uint16_t *)(buf + len + 16) = htobe16 (encryptedLen); + i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, header->mac); + } + + void SSUSession::Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey) + { + if (len < sizeof (SSUHeader)) + { + LogPrint ("Unexpected SSU packet length ", len); + return; + } + SSUHeader * header = (SSUHeader *)buf; + uint8_t * encrypted = &header->flag; + uint16_t encryptedLen = len - (encrypted - buf); + m_Decryption.SetKeyWithIV (aesKey, 32, header->iv); + m_Decryption.ProcessData (encrypted, encrypted, encryptedLen); + } + + bool SSUSession::Validate (uint8_t * buf, size_t len, uint8_t * macKey) + { + if (len < sizeof (SSUHeader)) + { + LogPrint ("Unexpected SSU packet length ", len); + return false; + } + SSUHeader * header = (SSUHeader *)buf; + uint8_t * encrypted = &header->flag; + uint16_t encryptedLen = len - (encrypted - buf); + // assume actual buffer size is 18 (16 + 2) bytes more + memcpy (buf + len, header->iv, 16); + *(uint16_t *)(buf + len + 16) = htobe16 (encryptedLen); + uint8_t digest[16]; + i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, digest); + return !memcmp (header->mac, digest, 16); } SSUServer::SSUServer (boost::asio::io_service& service, int port): @@ -47,6 +121,11 @@ namespace ssu m_Socket.close (); } + void SSUServer::Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to) + { + m_Socket.send_to (boost::asio::buffer (buf, len), to); + } + void SSUServer::Receive () { m_Socket.async_receive_from (boost::asio::buffer (m_ReceiveBuffer, SSU_MTU), m_SenderEndpoint, @@ -62,9 +141,9 @@ namespace ssu auto it = m_Sessions.find (m_SenderEndpoint); if (it != m_Sessions.end ()) session = it->second; - if (session) + if (!session) { - session = new SSUSession (); + session = new SSUSession (this, m_SenderEndpoint); m_Sessions[m_SenderEndpoint] = session; LogPrint ("New SSU session from ", m_SenderEndpoint.address ().to_string (), ":", m_SenderEndpoint.port (), " created"); } @@ -74,6 +153,33 @@ namespace ssu else LogPrint ("SSU receive error: ", ecode.message ()); } + + SSUSession * SSUServer::GetSession (i2p::data::RouterInfo * router) + { + SSUSession * session = nullptr; + if (router) + { + auto address = router->GetSSUAddress (); + if (address) + { + boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); + auto it = m_Sessions.find (remoteEndpoint); + if (it != m_Sessions.end ()) + session = it->second; + else + { + // otherwise create new session + session = new SSUSession (this, remoteEndpoint, router); + m_Sessions[remoteEndpoint] = session; + LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ", + remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created"); + } + } + else + LogPrint ("Router ", router->GetIdentHashAbbreviation (), " doesn't have SSU address"); + } + return session; + } } } diff --git a/SSU.h b/SSU.h index 073184f3..0b4843bf 100644 --- a/SSU.h +++ b/SSU.h @@ -7,6 +7,7 @@ #include #include #include "I2PEndian.h" +#include "RouterInfo.h" namespace i2p { @@ -46,21 +47,30 @@ namespace ssu eSessionStateEstablised }; + class SSUServer; class SSUSession { public: - SSUSession (); - void ProcessNextMessage (uint8_t * buf, size_t len); - + SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint, + i2p::data::RouterInfo * router = nullptr); + void ProcessNextMessage (uint8_t * buf, size_t len); + private: - void Authenticate (uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); + void ProcessSessionRequest (uint8_t * buf, size_t len); + + void Encrypt (uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); + void Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey); + bool Validate (uint8_t * buf, size_t len, uint8_t * macKey); private: + SSUServer * m_Server; + boost::asio::ip::udp::endpoint m_RemoteEndpoint; SessionState m_State; - CryptoPP::CBC_Mode::Encryption m_Encryption; + CryptoPP::CBC_Mode::Encryption m_Encryption; + CryptoPP::CBC_Mode::Decryption m_Decryption; }; class SSUServer @@ -71,6 +81,9 @@ namespace ssu ~SSUServer (); void Start (); void Stop (); + SSUSession * GetSession (i2p::data::RouterInfo * router); + + void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); private: @@ -81,7 +94,7 @@ namespace ssu boost::asio::ip::udp::socket m_Socket; boost::asio::ip::udp::endpoint m_SenderEndpoint; - uint8_t m_ReceiveBuffer[SSU_MTU]; + uint8_t m_ReceiveBuffer[2*SSU_MTU]; std::map m_Sessions; }; } From 73ee4ff34cd2057c804a98c6f809a18d725a99a3 Mon Sep 17 00:00:00 2001 From: Meeh Date: Wed, 29 Jan 2014 19:31:19 +0100 Subject: [PATCH 11/46] gitignore update --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 3c69f891..2cb9ea10 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ *.o router.info router.keys +i2p +netDb ################# ## Eclipse From ee77bba5e0631c187a958e17c4de288df4c4bbe7 Mon Sep 17 00:00:00 2001 From: Meeh Date: Wed, 29 Jan 2014 19:36:20 +0100 Subject: [PATCH 12/46] Create netDb directory structure --- NetDb.cpp | 69 +++++++++++++++++++++++++++++++++++++++++-------------- NetDb.h | 1 + 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 38814549..ee9a0a52 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -177,43 +177,75 @@ namespace data return it->second; else return nullptr; - } + } + + // TODO: Move to reseed and/or scheduled tasks. (In java version, scheduler fix this as well as sort RIs.) + bool NetDb::CreateNetDb(const char * directory) + { + boost::filesystem::path p (directory); + LogPrint (directory, " doesn't exist, trying to create it."); + if (!boost::filesystem::create_directory (p)) + { + LogPrint("Failed to create directory ", directory); + return false; + } + + // Random chars + std::string chars = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-~"; + boost::filesystem::path suffix; + for (auto c : chars) + { +#ifndef _WIN32 + suffix = "/r"; +#else + suffix = "\\r"; +#endif + suffix += c; + if (!boost::filesystem::create_directory( boost::filesystem::path (p / suffix) )) return false; + } + return true; + } void NetDb::Load (const char * directory) { boost::filesystem::path p (directory); - if (boost::filesystem::exists (p)) + if (!boost::filesystem::exists (p)) { - int numRouters = 0; - boost::filesystem::directory_iterator end; - for (boost::filesystem::directory_iterator it (p); it != end; ++it) + if (!CreateNetDb(directory)) return; + } + // TODO: Reseed if needed. + int numRouters = 0; + boost::filesystem::directory_iterator end; + for (boost::filesystem::directory_iterator it (p); it != end; ++it) + { + if (boost::filesystem::is_directory (it->status())) { - if (boost::filesystem::is_directory (it->status())) + for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1) { - for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1) - { #if BOOST_VERSION > 10500 - RouterInfo * r = new RouterInfo (it1->path().string().c_str ()); + RouterInfo * r = new RouterInfo (it1->path().string().c_str ()); #else - RouterInfo * r = new RouterInfo(it1->path().c_str()); + RouterInfo * r = new RouterInfo(it1->path().c_str()); #endif - m_RouterInfos[r->GetIdentHash ()] = r; - numRouters++; - } + m_RouterInfos[r->GetIdentHash ()] = r; + numRouters++; } } - LogPrint (numRouters, " routers loaded"); } - else - LogPrint (directory, " doesn't exist"); + LogPrint (numRouters, " routers loaded"); } void NetDb::SaveUpdated (const char * directory) { auto GetFilePath = [](const char * directory, const RouterInfo * routerInfo) { +#ifndef _WIN32 return std::string (directory) + "/r" + - routerInfo->GetIdentHashBase64 ()[0] + "/routerInfo-" + + routerInfo->GetIdentHashBase64 ()[0] + "/routerInfo-" + +#else + return std::string (directory) + "\\r" + + routerInfo->GetIdentHashBase64 ()[0] + "\\routerInfo-" + +#endif routerInfo->GetIdentHashBase64 () + ".dat"; }; @@ -570,6 +602,9 @@ namespace data return r; } + //TODO: Move to reseed. + //TODO: Implement v1 & v2 reseeding. Lightweight zip library is needed for v2. + //TODO: Implement SU3, utils. void NetDb::DownloadRouterInfo (const std::string& address, const std::string& filename) { try diff --git a/NetDb.h b/NetDb.h index 7baebc5d..1397e9e4 100644 --- a/NetDb.h +++ b/NetDb.h @@ -76,6 +76,7 @@ namespace data private: + bool CreateNetDb(const char * directory); void Load (const char * directory); void SaveUpdated (const char * directory); void DownloadRouterInfo (const std::string& address, const std::string& filename); // for reseed From 21693fc1e507997def521e621bda525f6c93a8f3 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2014 16:49:53 -0500 Subject: [PATCH 13/46] handle and send SessionRequest message --- SSU.cpp | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++----- SSU.h | 22 +++++++--- 2 files changed, 137 insertions(+), 16 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 5cb7cfe5..8d4be872 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -1,6 +1,10 @@ #include #include +#include +#include +#include "CryptoConst.h" #include "Log.h" +#include "Timestamp.h" #include "RouterContext.h" #include "hmac.h" #include "SSU.h" @@ -12,24 +16,110 @@ namespace ssu SSUSession::SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint, i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint), - m_State (eSessionStateUnknown) + m_RemoteRouter (router), m_State (eSessionStateUnknown) { } - void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len) + void SSUSession::CreateAESKey (uint8_t * pubKey, uint8_t * aesKey) // TODO: move it to base class for NTCP and SSU + { + CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); + CryptoPP::SecByteBlock secretKey(dh.AgreedValueLength()); + if (!dh.Agree (secretKey, i2p::context.GetPrivateKey (), pubKey)) + { + LogPrint ("Couldn't create shared key"); + return; + }; + + if (secretKey[0] & 0x80) + { + aesKey[0] = 0; + memcpy (aesKey + 1, secretKey, 31); + } + else + memcpy (aesKey, secretKey, 32); + } + + void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { switch (m_State) { case eSessionStateUnknown: - // we assume session request - ProcessSessionRequest (buf, len); + // session request + ProcessSessionRequest (buf, len, senderEndpoint); + break; + case eSessionStateRequestSent: + // session created + ProcessSessionCreated (buf, len); break; default: LogPrint ("SSU state not implemented yet"); } } - void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len) + void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) + { + LogPrint ("Process session request"); + if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, buf, len)) + { + m_State = eSessionStateRequestReceived; + LogPrint ("Session request received"); + SendSessionCreated (senderEndpoint); + } + } + + void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len) + { + LogPrint ("Process session created"); + if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, buf, len)) + { + m_State = eSessionStateCreatedReceived; + LogPrint ("Session request received"); + // TODO: + } + } + + void SSUSession::SendSessionRequest () + { + auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr; + if (!address) + { + LogPrint ("Missing remote SSU address"); + return; + } + + uint8_t buf[304 + 18]; // 304 bytes for ipv4 (320 for ipv6) + uint8_t * payload = buf + sizeof (SSUHeader); + memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256); + payload[256] = 4; // we assume ipv4 + *(uint32_t *)(payload + 257) = address->host.to_v4 ().to_ulong (); // network bytes order already + + uint8_t iv[16]; + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (iv, 16); // random iv + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, 304, address->key, iv, address->key); + + m_State = eSessionStateRequestSent; + m_Server->Send (buf, 304, m_RemoteEndpoint); + } + + void SSUSession::SendSessionCreated (const boost::asio::ip::udp::endpoint& senderEndpoint) + { + auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr; + if (!address) + { + LogPrint ("Missing remote SSU address"); + return; + } + + uint8_t buf[368 + 18]; + uint8_t * payload = buf + sizeof (SSUHeader); + memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256); + + m_State = eSessionStateRequestSent; + m_Server->Send (buf, 368, m_RemoteEndpoint); + } + + bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len) { auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); if (address) @@ -37,19 +127,25 @@ namespace ssu // use intro key for verification and decryption if (Validate (buf, len, address->key)) { - m_State = eSessionStateRequestReceived; - LogPrint ("Session request received"); Decrypt (buf, len, address->key); - // TODO: + SSUHeader * header = (SSUHeader *)buf; + if ((header->flag >> 4) == expectedPayloadType) + { + CreateAESKey (buf + sizeof (SSUHeader), m_SessionKey); + return true; + } + else + LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); } else LogPrint ("MAC verifcation failed"); } else LogPrint ("SSU is not supported"); - } + return false; + } - void SSUSession::Encrypt (uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey) + void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey) { if (len < sizeof (SSUHeader)) { @@ -58,6 +154,8 @@ namespace ssu } SSUHeader * header = (SSUHeader *)buf; memcpy (header->iv, iv, 16); + header->flag = payloadType << 4; // MSB is 0 + header->time = htobe32 (i2p::util::GetSecondsSinceEpoch ()); uint8_t * encrypted = &header->flag; uint16_t encryptedLen = len - (encrypted - buf); m_Encryption.SetKeyWithIV (aesKey, 32, iv); @@ -100,6 +198,16 @@ namespace ssu return !memcmp (header->mac, digest, 16); } + void SSUSession::Connect () + { + SendSessionRequest (); + } + + void SSUSession::SendI2NPMessage (I2NPMessage * msg) + { + // TODO: + } + SSUServer::SSUServer (boost::asio::io_service& service, int port): m_Socket (service, boost::asio::ip::udp::v4 (), port) { @@ -147,7 +255,7 @@ namespace ssu m_Sessions[m_SenderEndpoint] = session; LogPrint ("New SSU session from ", m_SenderEndpoint.address ().to_string (), ":", m_SenderEndpoint.port (), " created"); } - session->ProcessNextMessage (m_ReceiveBuffer, bytes_transferred); + session->ProcessNextMessage (m_ReceiveBuffer, bytes_transferred, m_SenderEndpoint); Receive (); } else @@ -173,6 +281,7 @@ namespace ssu m_Sessions[remoteEndpoint] = session; LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ", remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created"); + session->Connect (); } } else diff --git a/SSU.h b/SSU.h index 0b4843bf..d8ae7090 100644 --- a/SSU.h +++ b/SSU.h @@ -8,6 +8,7 @@ #include #include "I2PEndian.h" #include "RouterInfo.h" +#include "I2NPProtocol.h" namespace i2p { @@ -25,7 +26,7 @@ namespace ssu const int SSU_MTU = 1484; - // payload types (4 bits) + // payload types (3 bits) const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0; const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1; const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2; @@ -54,13 +55,22 @@ namespace ssu SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint, i2p::data::RouterInfo * router = nullptr); - void ProcessNextMessage (uint8_t * buf, size_t len); + void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); + + void Connect (); + void SendI2NPMessage (I2NPMessage * msg); private: - void ProcessSessionRequest (uint8_t * buf, size_t len); + void CreateAESKey (uint8_t * pubKey, uint8_t * aesKey); // TODO: shouldn't be here - void Encrypt (uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); + void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); + void SendSessionRequest (); + void ProcessSessionCreated (uint8_t * buf, size_t len); + void SendSessionCreated (const boost::asio::ip::udp::endpoint& senderEndpoint); + + bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len); + void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); void Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey); bool Validate (uint8_t * buf, size_t len, uint8_t * macKey); @@ -68,9 +78,11 @@ namespace ssu SSUServer * m_Server; boost::asio::ip::udp::endpoint m_RemoteEndpoint; + i2p::data::RouterInfo * m_RemoteRouter; SessionState m_State; CryptoPP::CBC_Mode::Encryption m_Encryption; - CryptoPP::CBC_Mode::Decryption m_Decryption; + CryptoPP::CBC_Mode::Decryption m_Decryption; + uint8_t m_SessionKey[32]; }; class SSUServer From 7c471d99c3e546b9ec469bae90a179976e16b175 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2014 17:38:11 -0500 Subject: [PATCH 14/46] use base64 alphabet directly --- NetDb.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index ee9a0a52..f150d283 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -190,17 +190,17 @@ namespace data return false; } - // Random chars - std::string chars = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-~"; + // list of chars might appear in base64 string + const char * chars = GetBase64SubstitutionTable (); boost::filesystem::path suffix; - for (auto c : chars) + while (*chars) { #ifndef _WIN32 - suffix = "/r"; + suffix = std::string ("/r") + *chars; #else - suffix = "\\r"; + suffix = std::string ("\\r") + *chars; #endif - suffix += c; + chars++; if (!boost::filesystem::create_directory( boost::filesystem::path (p / suffix) )) return false; } return true; @@ -604,6 +604,7 @@ namespace data //TODO: Move to reseed. //TODO: Implement v1 & v2 reseeding. Lightweight zip library is needed for v2. + // orignal: zip is part of crypto++, see implementation of DatabaseStoreMsg //TODO: Implement SU3, utils. void NetDb::DownloadRouterInfo (const std::string& address, const std::string& filename) { From 95b40c0c302e35516e90565b309c60dae2bdf8a3 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2014 17:38:53 -0500 Subject: [PATCH 15/46] use base64 alphabet directly --- base64.cpp | 5 +++++ base64.h | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/base64.cpp b/base64.cpp index b75214c9..e731bedc 100644 --- a/base64.cpp +++ b/base64.cpp @@ -27,6 +27,11 @@ namespace data '4', '5', '6', '7', '8', '9', '-', '~' }; + const char * GetBase64SubstitutionTable () + { + return T64; + } + /* * Reverse Substitution Table (built in run time) */ diff --git a/base64.h b/base64.h index d67927e9..47a65def 100644 --- a/base64.h +++ b/base64.h @@ -11,9 +11,9 @@ namespace data size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len); size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len ); - + const char * GetBase64SubstitutionTable (); + size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen); - } } From c361b7d9147146ca5d794b79b8ced75502955891 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2014 17:43:20 -0500 Subject: [PATCH 16/46] use base64 alphabet directly --- NetDb.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index f150d283..278e8286 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -191,16 +191,15 @@ namespace data } // list of chars might appear in base64 string - const char * chars = GetBase64SubstitutionTable (); + const char * chars = GetBase64SubstitutionTable (); // 64 bytes boost::filesystem::path suffix; - while (*chars) + for (int i = 0; i < 64; i++) { #ifndef _WIN32 - suffix = std::string ("/r") + *chars; + suffix = std::string ("/r") + chars[i]; #else - suffix = std::string ("\\r") + *chars; + suffix = std::string ("\\r") + chars[i]; #endif - chars++; if (!boost::filesystem::create_directory( boost::filesystem::path (p / suffix) )) return false; } return true; From fb16e50c4d3be4876112145cbdba0135250b1517 Mon Sep 17 00:00:00 2001 From: Meeh Date: Thu, 30 Jan 2014 01:56:48 +0100 Subject: [PATCH 17/46] Adding lightweight option parser --- Makefile | 2 +- RouterContext.cpp | 1 + i2p.cpp | 9 ++++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ebe266b8..abe4238d 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CC = g++ CFLAGS = -g -Wall -std=c++0x OBJECTS = i2p.o base64.o NTCPSession.o RouterInfo.o Transports.o RouterContext.o \ NetDb.o LeaseSet.o Tunnel.o TunnelEndpoint.o TunnelGateway.o TransitTunnel.o \ - I2NPProtocol.o Log.o Garlic.o HTTPServer.o Streaming.o Identity.o SSU.o + I2NPProtocol.o Log.o Garlic.o HTTPServer.o Streaming.o Identity.o SSU.o util.o INCFLAGS = LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lpthread LIBS = diff --git a/RouterContext.cpp b/RouterContext.cpp index 75a3eb51..68f6508a 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -3,6 +3,7 @@ #include #include "CryptoConst.h" #include "RouterContext.h" +#include "util.h" namespace i2p { diff --git a/i2p.cpp b/i2p.cpp index 51c6d1eb..67408fa6 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -10,10 +10,11 @@ #include "Tunnel.h" #include "NetDb.h" #include "HTTPServer.h" +#include "util.h" -int main( int, char** ) +int main( int argc, char* argv[] ) { - + i2p::util::ParseArguments(argc,argv); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); @@ -21,7 +22,9 @@ int main( int, char** ) setlocale(LC_ALL, "Russian"); #endif - i2p::util::HTTPServer httpServer (7070); + int httpport = i2p::util::GetIntArg("--httpport", 7070); + + i2p::util::HTTPServer httpServer (httpport); httpServer.Start (); i2p::data::netdb.Start (); From 611ab9ce8d56835db6b49c2146c6b0f1608fcd14 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2014 22:14:05 -0500 Subject: [PATCH 18/46] endpoint for SSU server --- SSU.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SSU.cpp b/SSU.cpp index 8d4be872..bfae3d0f 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -209,7 +209,7 @@ namespace ssu } SSUServer::SSUServer (boost::asio::io_service& service, int port): - m_Socket (service, boost::asio::ip::udp::v4 (), port) + m_Socket (service, boost::asio::ip::udp::endpoint (boost::asio::ip::udp::v4 (), port)) { } From 3b3f5d0188759bdec57ae23be3b171a2b69e079f Mon Sep 17 00:00:00 2001 From: Meeh Date: Thu, 30 Jan 2014 04:28:07 +0100 Subject: [PATCH 19/46] Missing files --- util.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ util.h | 19 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 util.cpp create mode 100644 util.h diff --git a/util.cpp b/util.cpp new file mode 100644 index 00000000..1f000f50 --- /dev/null +++ b/util.cpp @@ -0,0 +1,45 @@ +#include "util.h" + +namespace i2p +{ +namespace util +{ +std::map mapArgs; + +void ParseArguments(int argc, const char* const argv[]) +{ + mapArgs.clear(); + for (int i = 1; i < argc; i++) + { + std::string strKey (argv[i]); + std::string strValue; + size_t has_data = strKey.find('='); + if (has_data != std::string::npos) + { + strValue = strKey.substr(has_data+1); + strKey = strKey.substr(0, has_data); + } + if (strKey[0] != '-') + break; + + mapArgs[strKey] = strValue; + } +} + +int GetIntArg(const std::string& strArg, int nDefault) +{ + if (mapArgs.count(strArg)) + return atoi(mapArgs[strArg].c_str()); + return nDefault; +} + +std::string GetStringArg(const std::string& strArg, std::string nDefault) +{ + if (mapArgs.count(strArg)) + return mapArgs[strArg]; + return nDefault; +} + + +} // Namespace end +} diff --git a/util.h b/util.h new file mode 100644 index 00000000..ef015ded --- /dev/null +++ b/util.h @@ -0,0 +1,19 @@ +#ifndef UTIL_H +#define UTIL_H + +#include +#include + +namespace i2p +{ +namespace util +{ + extern std::map mapArgs; + void ParseArguments(int argc, const char* const argv[]); + int GetIntArg(const std::string& strArg, int nDefault); + +} +} + + +#endif From c4065a702e5911e21b4b793a0722edc41ad0bcfa Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2014 23:13:59 -0500 Subject: [PATCH 20/46] extract streaming packet fields --- Streaming.cpp | 34 ++++++++++------------------------ Streaming.h | 13 +++++++++++-- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/Streaming.cpp b/Streaming.cpp index 1a848c28..86f2a55c 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -31,26 +31,12 @@ namespace stream void Stream::HandleNextPacket (Packet * packet) { - const uint8_t * buf = packet->buf; - buf += 4; // sendStreamID if (!m_SendStreamID) - m_SendStreamID = be32toh (*(uint32_t *)buf); - buf += 4; // receiveStreamID - uint32_t receivedSeqn = be32toh (*(uint32_t *)buf); - buf += 4; // sequenceNum - buf += 4; // ackThrough - int nackCount = buf[0]; - buf++; // NACK count - buf += 4*nackCount; // NACKs - buf++; // resendDelay - uint16_t flags = be16toh (*(uint16_t *)buf); - buf += 2; // flags - uint16_t optionalSize = be16toh (*(uint16_t *)buf); - buf += 2; // optional size - const uint8_t * optionalData = buf; - buf += optionalSize; - + m_SendStreamID = packet->GetReceiveStreamID (); + // process flags + uint16_t flags = packet->GetFlags (); + const uint8_t * optionData = packet->GetOptionData (); if (flags & PACKET_FLAG_SYNCHRONIZE) { LogPrint ("Synchronize"); @@ -59,21 +45,21 @@ namespace stream if (flags & PACKET_FLAG_SIGNATURE_INCLUDED) { LogPrint ("Signature"); - optionalData += 40; + optionData += 40; } if (flags & PACKET_FLAG_FROM_INCLUDED) { LogPrint ("From identity"); - optionalData += sizeof (i2p::data::Identity); + optionData += sizeof (i2p::data::Identity); } - // we have reached payload section + uint32_t receivedSeqn = packet->GetSeqn (); LogPrint ("seqn=", receivedSeqn, ", flags=", flags); if (!receivedSeqn || receivedSeqn == m_LastReceivedSequenceNumber + 1) { // we have received next message - packet->offset = buf - packet->buf; + packet->offset = packet->GetPayload () - packet->buf; if (packet->GetLength () > 0) m_ReceiveQueue.Put (packet); else @@ -85,12 +71,12 @@ namespace stream // we should also try stored messages if any for (auto it = m_SavedPackets.begin (); it != m_SavedPackets.end ();) { - if ((*it)->GetReceivedSeqn () == m_LastReceivedSequenceNumber + 1) + if ((*it)->GetSeqn () == m_LastReceivedSequenceNumber + 1) { Packet * packet = *it; m_SavedPackets.erase (it++); - LogPrint ("Process saved packet seqn=", packet->GetReceivedSeqn ()); + LogPrint ("Process saved packet seqn=", packet->GetSeqn ()); if (packet->GetLength () > 0) m_ReceiveQueue.Put (packet); else diff --git a/Streaming.h b/Streaming.h index 248d8ee2..5939d058 100644 --- a/Streaming.h +++ b/Streaming.h @@ -40,14 +40,23 @@ namespace stream uint8_t * GetBuffer () { return buf + offset; }; size_t GetLength () const { return len - offset; }; - uint32_t GetReceivedSeqn () const { return be32toh (*(uint32_t *)(buf + 8)); }; + uint32_t GetSendStreamID () const { return be32toh (*(uint32_t *)buf); }; + uint32_t GetReceiveStreamID () const { return be32toh (*(uint32_t *)(buf + 4)); }; + uint32_t GetSeqn () const { return be32toh (*(uint32_t *)(buf + 8)); }; + uint32_t GetAckThrough () const { return be32toh (*(uint32_t *)(buf + 12)); }; + uint8_t GetNACKCount () const { return buf[16]; }; + const uint8_t * GetOption () const { return buf + 17 + GetNACKCount ()*4 + 3; }; // 3 = resendDelay + flags + uint16_t GetFlags () const { return be16toh (*(uint16_t *)(GetOption () - 2)); }; + uint16_t GetOptionSize () const { return be16toh (*(uint16_t *)GetOption ()); }; + const uint8_t * GetOptionData () const { return GetOption () + 2; }; + const uint8_t * GetPayload () const { return GetOptionData () + GetOptionSize (); }; }; struct PacketCmp { bool operator() (const Packet * p1, const Packet * p2) const { - return p1->GetReceivedSeqn () < p2->GetReceivedSeqn (); + return p1->GetSeqn () < p2->GetSeqn (); }; }; From 38bc15167c442c22a8fab449ef412bd978f861c9 Mon Sep 17 00:00:00 2001 From: Meeh Date: Thu, 30 Jan 2014 14:28:11 +0100 Subject: [PATCH 21/46] =?UTF-8?q?Fix.=20Thanks=20to=20zzz=20@=C2=A0#i2p-de?= =?UTF-8?q?v?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SSU.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SSU.h b/SSU.h index d8ae7090..3e7ec4f9 100644 --- a/SSU.h +++ b/SSU.h @@ -26,10 +26,11 @@ namespace ssu const int SSU_MTU = 1484; - // payload types (3 bits) + // payload types (4 bits) const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0; const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1; const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2; + const uint8_t PAYLOAD_TYPE_SESSION_DESTROY = 8; const uint8_t PAYLOAD_TYPE_RELAY_REQUEST = 3; const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4; const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5; From 732b17a368e342bd1a6e0344d393f9959a2c8724 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 30 Jan 2014 14:03:11 -0500 Subject: [PATCH 22/46] send SessionCreated message --- SSU.cpp | 38 ++++++++++++++++++++++++++++++++++---- SSU.h | 6 ++++-- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index bfae3d0f..1c7d0155 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -63,7 +63,8 @@ namespace ssu { m_State = eSessionStateRequestReceived; LogPrint ("Session request received"); - SendSessionCreated (senderEndpoint); + m_RemoteEndpoint = senderEndpoint; + SendSessionCreated (buf + sizeof (SSUHeader)); } } @@ -102,7 +103,7 @@ namespace ssu m_Server->Send (buf, 304, m_RemoteEndpoint); } - void SSUSession::SendSessionCreated (const boost::asio::ip::udp::endpoint& senderEndpoint) + void SSUSession::SendSessionCreated (const uint8_t * x) { auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr; if (!address) @@ -110,11 +111,40 @@ namespace ssu LogPrint ("Missing remote SSU address"); return; } + uint8_t signedData[532]; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time + memcpy (signedData, x, 256); // x - uint8_t buf[368 + 18]; + uint8_t buf[368 + 18]; uint8_t * payload = buf + sizeof (SSUHeader); memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256); + memcpy (signedData + 256, payload, 256); // y + payload += 256; + *payload = 4; // we assume ipv4 + payload++; + *(uint32_t *)(payload) = m_RemoteEndpoint.address ().to_v4 ().to_ulong (); // network bytes order already + payload += 4; + *(uint16_t *)(payload) = htobe16 (m_RemoteEndpoint.port ()); + payload += 2; + memcpy (signedData + 512, payload - 6, 6); // remote endpoint IP and port + *(uint32_t *)(signedData + 518) = m_Server->GetEndpoint ().address ().to_v4 ().to_ulong (); // our IP + *(uint16_t *)(signedData + 522) = htobe16 (m_Server->GetEndpoint ().port ()); // our port + *(uint32_t *)(payload) = 0; // relay tag, always 0 for now + payload += 4; + *(uint32_t *)(payload) = htobe32 (i2p::util::GetSecondsSinceEpoch ()); // signed on time + payload += 4; + memcpy (signedData + 524, payload - 8, 8); // relayTag and signed on time + i2p::context.Sign (signedData, 532, payload); // DSA signature + // TODO: fill padding with random data + uint8_t iv[16]; + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (iv, 16); // random iv + // encrypt signature and 8 bytes padding with newly created session key + m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv); + m_Encryption.ProcessData (payload, payload, 48); + + // encrypt message with intro key + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, address->key, iv, address->key); m_State = eSessionStateRequestSent; m_Server->Send (buf, 368, m_RemoteEndpoint); } @@ -209,7 +239,7 @@ namespace ssu } SSUServer::SSUServer (boost::asio::io_service& service, int port): - m_Socket (service, boost::asio::ip::udp::endpoint (boost::asio::ip::udp::v4 (), port)) + m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint) { } diff --git a/SSU.h b/SSU.h index 3e7ec4f9..6b2d108a 100644 --- a/SSU.h +++ b/SSU.h @@ -68,7 +68,7 @@ namespace ssu void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void SendSessionRequest (); void ProcessSessionCreated (uint8_t * buf, size_t len); - void SendSessionCreated (const boost::asio::ip::udp::endpoint& senderEndpoint); + void SendSessionCreated (const uint8_t * x); bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len); void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); @@ -95,7 +95,8 @@ namespace ssu void Start (); void Stop (); SSUSession * GetSession (i2p::data::RouterInfo * router); - + + const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); private: @@ -105,6 +106,7 @@ namespace ssu private: + boost::asio::ip::udp::endpoint m_Endpoint; boost::asio::ip::udp::socket m_Socket; boost::asio::ip::udp::endpoint m_SenderEndpoint; uint8_t m_ReceiveBuffer[2*SSU_MTU]; From 633c9becd919d8d8ac73a80fd04d9de081b6eea1 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 01:39:16 +0100 Subject: [PATCH 23/46] Adding more to the option parser. Adding instruction on how to test it. --- README.md | 30 ++++++++++++++++++++++++++++++ i2p.cpp | 5 ++++- util.cpp | 8 ++++---- util.h | 3 ++- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ab64cb4d..32eec060 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,33 @@ Requires gcc 4.6 and higher, boost 1.46 and higher, crypto++ on Windows Requires msvs2013, boost 1.46 and higher, crypto++ + + +Testing +------- + +First, build it. + +$ cd i2pd +$ make + +Now, copy your netDb folder from your Java I2P config dir. (The one with r0, r1, r2, ... folders in it) to the source folder where your i2p binary is. + +Next, find out your public ip. (find it for example at http://www.whatismyip.com/) + +Then, run it with: + +$ ./i2p --host=YOUR_PUBLIC_IP + + +Other options: +--port= - The port to listen on +--httpport= - The http port to listen on + + +To visit an I2P page, you need to find the b32 address of your destination. +After that, go to the webconsole and add it behind the url. (Remove http:// and b32.i2p from the address) + +This should resulting in for example: +http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa + diff --git a/i2p.cpp b/i2p.cpp index 67408fa6..5c0bd378 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -14,7 +14,7 @@ int main( int argc, char* argv[] ) { - i2p::util::ParseArguments(argc,argv); + i2p::util::OptionParser(argc,argv); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); @@ -22,6 +22,9 @@ int main( int argc, char* argv[] ) setlocale(LC_ALL, "Russian"); #endif + //TODO: This is an ugly workaround. fix it. + //TODO: Autodetect public IP. + i2p::context.OverrideNTCPAddress(i2p::util::GetCharArg("--host", "127.0.0.1"), i2p::util::GetIntArg("--port", 17070)); int httpport = i2p::util::GetIntArg("--httpport", 7070); i2p::util::HTTPServer httpServer (httpport); diff --git a/util.cpp b/util.cpp index 1f000f50..676fddd1 100644 --- a/util.cpp +++ b/util.cpp @@ -6,7 +6,7 @@ namespace util { std::map mapArgs; -void ParseArguments(int argc, const char* const argv[]) +void OptionParser(int argc, const char* const argv[]) { mapArgs.clear(); for (int i = 1; i < argc; i++) @@ -33,11 +33,11 @@ int GetIntArg(const std::string& strArg, int nDefault) return nDefault; } -std::string GetStringArg(const std::string& strArg, std::string nDefault) +const char* GetCharArg(const std::string& strArg, const std::string& nDefault) { if (mapArgs.count(strArg)) - return mapArgs[strArg]; - return nDefault; + return mapArgs[strArg].c_str(); + return nDefault.c_str(); } diff --git a/util.h b/util.h index ef015ded..fb3597e6 100644 --- a/util.h +++ b/util.h @@ -9,8 +9,9 @@ namespace i2p namespace util { extern std::map mapArgs; - void ParseArguments(int argc, const char* const argv[]); + void OptionParser(int argc, const char* const argv[]); int GetIntArg(const std::string& strArg, int nDefault); + const char* GetCharArg(const std::string& strArg, const std::string& nDefault); } } From e6ccffcf77d65978d8350817a26ca0904b4e8ad0 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 01:42:27 +0100 Subject: [PATCH 24/46] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 32eec060..3117f52a 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ Testing First, build it. -$ cd i2pd -$ make +* $ cd i2pd +* $ make Now, copy your netDb folder from your Java I2P config dir. (The one with r0, r1, r2, ... folders in it) to the source folder where your i2p binary is. @@ -28,8 +28,8 @@ $ ./i2p --host=YOUR_PUBLIC_IP Other options: ---port= - The port to listen on ---httpport= - The http port to listen on +* --port= - The port to listen on +* --httpport= - The http port to listen on To visit an I2P page, you need to find the b32 address of your destination. From b4e2c7ee87e8987ec63fdd4f3e960d478b1d124b Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 02:49:06 +0100 Subject: [PATCH 25/46] Updating Makefile to collect build objects in a folder --- .gitignore | 2 +- Makefile | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 2cb9ea10..0e609a70 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # i2pd -*.o +obj/*.o router.info router.keys i2p diff --git a/Makefile b/Makefile index abe4238d..5a3e6336 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,28 @@ CC = g++ CFLAGS = -g -Wall -std=c++0x -OBJECTS = i2p.o base64.o NTCPSession.o RouterInfo.o Transports.o RouterContext.o \ - NetDb.o LeaseSet.o Tunnel.o TunnelEndpoint.o TunnelGateway.o TransitTunnel.o \ - I2NPProtocol.o Log.o Garlic.o HTTPServer.o Streaming.o Identity.o SSU.o util.o +OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \ + obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \ + obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \ + obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o INCFLAGS = LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lpthread LIBS = all: i2p -i2p: $(OBJECTS) - $(CC) -o i2p $(OBJECTS) $(LDFLAGS) $(LIBS) +i2p: $(OBJECTS:obj/%=obj/%) + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) .SUFFIXES: .SUFFIXES: .c .cc .C .cpp .o -.cpp.o : - $(CC) -o $@ -c $(CFLAGS) $< $(INCFLAGS) +obj/%.o : %.cpp + mkdir -p obj + $(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) clean: - rm -f *.o + rm -fr obj .PHONY: all .PHONY: clean From e6e74efc26ec381d6fe49ffa57e532c939a570c5 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 30 Jan 2014 22:23:13 -0500 Subject: [PATCH 26/46] call mkdir only once --- Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 5a3e6336..370b3a0a 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ INCFLAGS = LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lpthread LIBS = -all: i2p +all: obj i2p i2p: $(OBJECTS:obj/%=obj/%) $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) @@ -18,11 +18,14 @@ i2p: $(OBJECTS:obj/%=obj/%) .SUFFIXES: .c .cc .C .cpp .o obj/%.o : %.cpp - mkdir -p obj $(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) +obj: + mkdir -p obj + clean: - rm -fr obj + rm -fr obj i2p .PHONY: all .PHONY: clean + From 86355cfe09278ff158bf45192451da0017dd72b2 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 07:22:11 +0100 Subject: [PATCH 27/46] Adding reseed support. v1, only http so far. --- Makefile | 4 +-- NetDb.cpp | 56 +++++++++----------------------- NetDb.h | 3 +- Reseed.cpp | 70 ++++++++++++++++++++++++++++++++++++++++ Reseed.h | 28 ++++++++++++++++ util.cpp | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ util.h | 12 ++++++- 7 files changed, 223 insertions(+), 45 deletions(-) create mode 100644 Reseed.cpp create mode 100644 Reseed.h diff --git a/Makefile b/Makefile index 5a3e6336..5c2e61fb 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,9 @@ CFLAGS = -g -Wall -std=c++0x OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \ obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \ obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \ - obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o + obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o INCFLAGS = -LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lpthread +LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lpthread LIBS = all: i2p diff --git a/NetDb.cpp b/NetDb.cpp index 278e8286..4d4ce103 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -13,6 +13,7 @@ #include "RouterContext.h" #include "Garlic.h" #include "NetDb.h" +#include "Reseed.h" namespace i2p { @@ -207,12 +208,23 @@ namespace data void NetDb::Load (const char * directory) { + Load(directory, false); + } + + void NetDb::Load (const char * directory, bool reseed) + { + i2p::data::Reseeder *reseeder = new i2p::data::Reseeder(); boost::filesystem::path p (directory); if (!boost::filesystem::exists (p)) { if (!CreateNetDb(directory)) return; + reseeder->reseedNow(); + } + if (reseed) + { + reseeder->reseedNow(); + m_reseedRetries++; } - // TODO: Reseed if needed. int numRouters = 0; boost::filesystem::directory_iterator end; for (boost::filesystem::directory_iterator it (p); it != end; ++it) @@ -232,6 +244,8 @@ namespace data } } LogPrint (numRouters, " routers loaded"); + if (numRouters < 100 && m_reseedRetries < 10) + Load(directory, true); // Reseed } void NetDb::SaveUpdated (const char * directory) @@ -601,45 +615,5 @@ namespace data return r; } - //TODO: Move to reseed. - //TODO: Implement v1 & v2 reseeding. Lightweight zip library is needed for v2. - // orignal: zip is part of crypto++, see implementation of DatabaseStoreMsg - //TODO: Implement SU3, utils. - void NetDb::DownloadRouterInfo (const std::string& address, const std::string& filename) - { - try - { - boost::asio::ip::tcp::iostream site(address, "http"); - if (!site) - { - //site.expires_from_now (boost::posix_time::seconds (10)); // wait for 10 seconds - site << "GET " << filename << "HTTP/1.0\nHost: " << address << "\nAccept: */*\nConnection: close\n\n"; - // read response - std::string version, statusMessage; - site >> version; // HTTP version - int status; - site >> status; // status - std::getline (site, statusMessage); - if (status == 200) // OK - { - std::string header; - while (header != "\n") - std::getline (site, header); - // read content - std::stringstream ss; - ss << site.rdbuf(); - AddRouterInfo ((uint8_t *)ss.str ().c_str (), ss.str ().size ()); - } - else - LogPrint ("HTTP response ", status); - } - else - LogPrint ("Can't connect to ", address); - } - catch (std::exception& ex) - { - LogPrint ("Failed to download ", filename, " : ", ex.what ()); - } - } } } diff --git a/NetDb.h b/NetDb.h index 1397e9e4..ddf50d06 100644 --- a/NetDb.h +++ b/NetDb.h @@ -78,8 +78,8 @@ namespace data bool CreateNetDb(const char * directory); void Load (const char * directory); + void Load (const char * directory, bool reseed); void SaveUpdated (const char * directory); - void DownloadRouterInfo (const std::string& address, const std::string& filename); // for reseed void Run (); // exploratory thread void Explore (); const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set& excluded) const; @@ -95,6 +95,7 @@ namespace data std::map m_RequestedDestinations; bool m_IsRunning; + int m_reseedRetries = 0; std::thread * m_Thread; i2p::util::Queue m_Queue; // of I2NPDatabaseStoreMsg }; diff --git a/Reseed.cpp b/Reseed.cpp new file mode 100644 index 00000000..cc61e4ef --- /dev/null +++ b/Reseed.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include "Reseed.h" +#include "Log.h" +#include "util.h" + + +namespace i2p +{ +namespace data +{ + + Reseeder::Reseeder() + { + } + + Reseeder::~Reseeder() + { + } + + bool Reseeder::reseedNow() + { + try + { + std::string reseedHost = httpReseedHostList[(rand() % httpReseedHostList.size())]; + LogPrint("Reseeding from ", reseedHost); + std::string content = i2p::util::http::httpRequest(reseedHost); + if (content == "") + { + LogPrint("Reseed failed"); + return false; + } + boost::regex e("<\\s*A\\s+[^>]*href\\s*=\\s*\"([^\"]*)\"", + boost::regex::normal | boost::regbase::icase); + boost::sregex_token_iterator i(content.begin(), content.end(), e, 1); + boost::sregex_token_iterator j; + std::string name; + std::string routerInfo; + std::string tmpUrl; + std::string filename; + while (i != j) + { + name = *i++; + LogPrint("Downloading ", name); + tmpUrl = reseedHost; + tmpUrl.append(name); + routerInfo = i2p::util::http::httpRequest(tmpUrl); + filename = "netDb/r"; + filename += name.at(11); + filename.append("/"); + filename.append(name.c_str()); + std::ofstream outfile (filename, std::ios::binary); + outfile << routerInfo; + outfile.close(); + } + return true; + } + catch (std::exception& ex) + { + //TODO: error reporting + return false; + } + return false; + } + +} +} + diff --git a/Reseed.h b/Reseed.h new file mode 100644 index 00000000..ac5a7cd7 --- /dev/null +++ b/Reseed.h @@ -0,0 +1,28 @@ +#ifndef RESEED_H +#define RESEED_H + +#include +#include + +namespace i2p +{ +namespace data +{ + + class Reseeder + { + public: + Reseeder(); + ~Reseeder(); + bool reseedNow(); + private: + std::vector httpReseedHostList = { + "http://193.150.121.66/netDb/", + "http://netdb.i2p2.no/" + }; + }; + +} +} + +#endif \ No newline at end of file diff --git a/util.cpp b/util.cpp index 676fddd1..a101dfe4 100644 --- a/util.cpp +++ b/util.cpp @@ -1,4 +1,11 @@ +#include +#include +#include +#include +#include +#include #include "util.h" +#include "Log.h" namespace i2p { @@ -40,6 +47,94 @@ const char* GetCharArg(const std::string& strArg, const std::string& nDefault) return nDefault.c_str(); } +namespace http +{ +//const std::string& filename +//AddRouterInfo ((uint8_t *)ss.str ().c_str (), ss.str ().size ()); + //TODO: Move to reseed. + //TODO: Implement v1 & v2 reseeding. Lightweight zip library is needed for v2. + // orignal: zip is part of crypto++, see implementation of DatabaseStoreMsg + //TODO: Implement SU3, utils. + std::string httpRequest(const std::string& address) + { + try + { + i2p::util::http::url u(address); + boost::asio::ip::tcp::iostream site; + site.expires_from_now (boost::posix_time::seconds(30)); + site.connect(u.host_, "http"); + if (site) + { + //site.expires_from_now (boost::posix_time::seconds (10)); // wait for 10 seconds + // User-Agent is needed to get the server list routerInfo files. + site << "GET " << u.path_ << " HTTP/1.0\r\nHost: " << u.host_ + << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n"; + // read response + std::string version, statusMessage; + site >> version; // HTTP version + int status; + site >> status; // status + std::getline (site, statusMessage); + if (status == 200) // OK + { + std::string header; + while (std::getline(site, header) && header != "\r"){} + std::stringstream ss; + ss << site.rdbuf(); + return ss.str(); + } + else + { + LogPrint ("HTTP response ", status); + return ""; + } + } + else + { + LogPrint ("Can't connect to ", address); + return ""; + } + } + catch (std::exception& ex) + { + LogPrint ("Failed to download ", address, " : ", ex.what ()); + return ""; + } + } + + url::url(const std::string& url_s) + { + parse(url_s); + } + + void url::parse(const std::string& url_s) + { + const std::string prot_end("://"); + std::string::const_iterator prot_i = search(url_s.begin(), url_s.end(), + prot_end.begin(), prot_end.end()); + protocol_.reserve(distance(url_s.begin(), prot_i)); + transform(url_s.begin(), prot_i, + back_inserter(protocol_), + std::ptr_fun(tolower)); // protocol is icase + if( prot_i == url_s.end() ) + return; + advance(prot_i, prot_end.length()); + std::string::const_iterator path_i = find(prot_i, url_s.end(), '/'); + host_.reserve(distance(prot_i, path_i)); + transform(prot_i, path_i, + back_inserter(host_), + std::ptr_fun(tolower)); // host is icase + std::string::const_iterator query_i = find(path_i, url_s.end(), '?'); + path_.assign(path_i, query_i); + if( query_i != url_s.end() ) + ++query_i; + query_.assign(query_i, url_s.end()); + } + +} + + + } // Namespace end } diff --git a/util.h b/util.h index fb3597e6..7643e0d0 100644 --- a/util.h +++ b/util.h @@ -12,7 +12,17 @@ namespace util void OptionParser(int argc, const char* const argv[]); int GetIntArg(const std::string& strArg, int nDefault); const char* GetCharArg(const std::string& strArg, const std::string& nDefault); - + namespace http + { + std::string httpRequest(const std::string& address); + struct url { + url(const std::string& url_s); // omitted copy, ==, accessors, ... + private: + void parse(const std::string& url_s); + public: + std::string protocol_, host_, path_, query_; + }; + } } } From 83bd3c21ca6fc92d3d87567113f226a811effd56 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 07:31:06 +0100 Subject: [PATCH 28/46] Adding more reseed hosts Ignore zip files --- Reseed.cpp | 4 ++++ Reseed.h | 10 +++++++++- util.cpp | 6 +----- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Reseed.cpp b/Reseed.cpp index cc61e4ef..05825f6a 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -40,9 +40,13 @@ namespace data std::string routerInfo; std::string tmpUrl; std::string filename; + std::string ignoreFileSuffix = ".zip"; while (i != j) { + //TODO: Ugly code, try to clean up. name = *i++; + if (name.find(ignoreFileSuffix)!=std::string::npos) + continue; LogPrint("Downloading ", name); tmpUrl = reseedHost; tmpUrl.append(name); diff --git a/Reseed.h b/Reseed.h index ac5a7cd7..96ce9c55 100644 --- a/Reseed.h +++ b/Reseed.h @@ -18,7 +18,15 @@ namespace data private: std::vector httpReseedHostList = { "http://193.150.121.66/netDb/", - "http://netdb.i2p2.no/" + "http://netdb.i2p2.no/", + "http://reseed.i2p-projekt.de/", + "http://cowpuncher.drollette.com/netdb/", + "http://i2p.mooo.com/netDb/", + "http://reseed.info/", + "http://reseed.pkol.de/", + "http://uk.reseed.i2p2.no/", + "http://i2p-netdb.innovatio.no/", + "http://ieb9oopo.mooo.com" }; }; diff --git a/util.cpp b/util.cpp index a101dfe4..5834e2ab 100644 --- a/util.cpp +++ b/util.cpp @@ -49,11 +49,7 @@ const char* GetCharArg(const std::string& strArg, const std::string& nDefault) namespace http { -//const std::string& filename -//AddRouterInfo ((uint8_t *)ss.str ().c_str (), ss.str ().size ()); - //TODO: Move to reseed. - //TODO: Implement v1 & v2 reseeding. Lightweight zip library is needed for v2. - // orignal: zip is part of crypto++, see implementation of DatabaseStoreMsg + //TODO: Implement v2 reseeding. Lightweight zip library is needed. //TODO: Implement SU3, utils. std::string httpRequest(const std::string& address) { From 9415a49fbd618ad0d770022628a5ac6784ddbb17 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 07:35:21 +0100 Subject: [PATCH 29/46] documentation update --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 3117f52a..dc4e0a8c 100644 --- a/README.md +++ b/README.md @@ -18,14 +18,13 @@ First, build it. * $ cd i2pd * $ make -Now, copy your netDb folder from your Java I2P config dir. (The one with r0, r1, r2, ... folders in it) to the source folder where your i2p binary is. - Next, find out your public ip. (find it for example at http://www.whatismyip.com/) Then, run it with: $ ./i2p --host=YOUR_PUBLIC_IP +The client should now reseed by itself. Other options: * --port= - The port to listen on From 849ab03e1c261d96c23db1ca094aa2ab0af984a4 Mon Sep 17 00:00:00 2001 From: Meeh Date: Fri, 31 Jan 2014 07:43:56 +0100 Subject: [PATCH 30/46] Cleanup and final comments --- Reseed.cpp | 12 ++++++------ util.cpp | 3 --- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Reseed.cpp b/Reseed.cpp index 05825f6a..1442b1b4 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include "Reseed.h" #include "Log.h" @@ -11,7 +10,8 @@ namespace i2p { namespace data { - + //TODO: Implement v2 reseeding. Lightweight zip library is needed. + //TODO: Implement SU3, utils. Reseeder::Reseeder() { } @@ -32,10 +32,11 @@ namespace data LogPrint("Reseed failed"); return false; } - boost::regex e("<\\s*A\\s+[^>]*href\\s*=\\s*\"([^\"]*)\"", - boost::regex::normal | boost::regbase::icase); + boost::regex e("<\\s*A\\s+[^>]*href\\s*=\\s*\"([^\"]*)\"", boost::regex::normal | boost::regbase::icase); boost::sregex_token_iterator i(content.begin(), content.end(), e, 1); boost::sregex_token_iterator j; + //TODO: Ugly code, try to clean up. + //TODO: Try to reduce N number of variables std::string name; std::string routerInfo; std::string tmpUrl; @@ -43,7 +44,6 @@ namespace data std::string ignoreFileSuffix = ".zip"; while (i != j) { - //TODO: Ugly code, try to clean up. name = *i++; if (name.find(ignoreFileSuffix)!=std::string::npos) continue; @@ -52,7 +52,7 @@ namespace data tmpUrl.append(name); routerInfo = i2p::util::http::httpRequest(tmpUrl); filename = "netDb/r"; - filename += name.at(11); + filename += name.at(11); // first char in id filename.append("/"); filename.append(name.c_str()); std::ofstream outfile (filename, std::ios::binary); diff --git a/util.cpp b/util.cpp index 5834e2ab..a33414ac 100644 --- a/util.cpp +++ b/util.cpp @@ -49,8 +49,6 @@ const char* GetCharArg(const std::string& strArg, const std::string& nDefault) namespace http { - //TODO: Implement v2 reseeding. Lightweight zip library is needed. - //TODO: Implement SU3, utils. std::string httpRequest(const std::string& address) { try @@ -61,7 +59,6 @@ namespace http site.connect(u.host_, "http"); if (site) { - //site.expires_from_now (boost::posix_time::seconds (10)); // wait for 10 seconds // User-Agent is needed to get the server list routerInfo files. site << "GET " << u.path_ << " HTTP/1.0\r\nHost: " << u.host_ << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n"; From 8d98722b4652c846107aac705764b65e72dfbc1e Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 31 Jan 2014 07:32:34 -0500 Subject: [PATCH 31/46] fixed compilation error in gcc 4.6 --- NetDb.cpp | 6 +++--- NetDb.h | 2 +- Reseed.cpp | 14 ++++++++++++++ Reseed.h | 13 ------------- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 4d4ce103..5f76a8c1 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -45,7 +45,7 @@ namespace data NetDb netdb; - NetDb::NetDb (): m_IsRunning (false), m_Thread (0) + NetDb::NetDb (): m_IsRunning (false), m_ReseedRetries (0), m_Thread (0) { } @@ -223,7 +223,7 @@ namespace data if (reseed) { reseeder->reseedNow(); - m_reseedRetries++; + m_ReseedRetries++; } int numRouters = 0; boost::filesystem::directory_iterator end; @@ -244,7 +244,7 @@ namespace data } } LogPrint (numRouters, " routers loaded"); - if (numRouters < 100 && m_reseedRetries < 10) + if (numRouters < 100 && m_ReseedRetries < 10) Load(directory, true); // Reseed } diff --git a/NetDb.h b/NetDb.h index ddf50d06..432036dc 100644 --- a/NetDb.h +++ b/NetDb.h @@ -95,7 +95,7 @@ namespace data std::map m_RequestedDestinations; bool m_IsRunning; - int m_reseedRetries = 0; + int m_ReseedRetries; std::thread * m_Thread; i2p::util::Queue m_Queue; // of I2NPDatabaseStoreMsg }; diff --git a/Reseed.cpp b/Reseed.cpp index 1442b1b4..540caa15 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -10,6 +10,20 @@ namespace i2p { namespace data { + + static std::vector httpReseedHostList = { + "http://193.150.121.66/netDb/", + "http://netdb.i2p2.no/", + "http://reseed.i2p-projekt.de/", + "http://cowpuncher.drollette.com/netdb/", + "http://i2p.mooo.com/netDb/", + "http://reseed.info/", + "http://reseed.pkol.de/", + "http://uk.reseed.i2p2.no/", + "http://i2p-netdb.innovatio.no/", + "http://ieb9oopo.mooo.com" + }; + //TODO: Implement v2 reseeding. Lightweight zip library is needed. //TODO: Implement SU3, utils. Reseeder::Reseeder() diff --git a/Reseed.h b/Reseed.h index 96ce9c55..3b07d840 100644 --- a/Reseed.h +++ b/Reseed.h @@ -15,19 +15,6 @@ namespace data Reseeder(); ~Reseeder(); bool reseedNow(); - private: - std::vector httpReseedHostList = { - "http://193.150.121.66/netDb/", - "http://netdb.i2p2.no/", - "http://reseed.i2p-projekt.de/", - "http://cowpuncher.drollette.com/netdb/", - "http://i2p.mooo.com/netDb/", - "http://reseed.info/", - "http://reseed.pkol.de/", - "http://uk.reseed.i2p2.no/", - "http://i2p-netdb.innovatio.no/", - "http://ieb9oopo.mooo.com" - }; }; } From 0e5bbfa21c6e63b7a842ac91471049f132ef8459 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 31 Jan 2014 13:08:33 -0500 Subject: [PATCH 32/46] avoid unnececssary recusion --- NetDb.cpp | 30 +++++++++++++++--------------- NetDb.h | 1 - 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 5f76a8c1..49c37562 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -63,6 +63,13 @@ namespace data void NetDb::Start () { Load ("netDb"); + while (m_RouterInfos.size () < 100 && m_ReseedRetries < 10) + { + Reseeder reseeder; + reseeder.reseedNow(); + m_ReseedRetries++; + Load ("netDb"); + } m_Thread = new std::thread (std::bind (&NetDb::Run, this)); } @@ -205,26 +212,21 @@ namespace data } return true; } - + void NetDb::Load (const char * directory) { - Load(directory, false); - } - - void NetDb::Load (const char * directory, bool reseed) - { - i2p::data::Reseeder *reseeder = new i2p::data::Reseeder(); boost::filesystem::path p (directory); if (!boost::filesystem::exists (p)) { + // seems netDb doesn't exist yet if (!CreateNetDb(directory)) return; - reseeder->reseedNow(); - } - if (reseed) - { - reseeder->reseedNow(); - m_ReseedRetries++; } + // make sure we cleanup netDb from previous attempts + for (auto r: m_RouterInfos) + delete r.second; + m_RouterInfos.clear (); + + // load routers now int numRouters = 0; boost::filesystem::directory_iterator end; for (boost::filesystem::directory_iterator it (p); it != end; ++it) @@ -244,8 +246,6 @@ namespace data } } LogPrint (numRouters, " routers loaded"); - if (numRouters < 100 && m_ReseedRetries < 10) - Load(directory, true); // Reseed } void NetDb::SaveUpdated (const char * directory) diff --git a/NetDb.h b/NetDb.h index 432036dc..3fb6ad10 100644 --- a/NetDb.h +++ b/NetDb.h @@ -78,7 +78,6 @@ namespace data bool CreateNetDb(const char * directory); void Load (const char * directory); - void Load (const char * directory, bool reseed); void SaveUpdated (const char * directory); void Run (); // exploratory thread void Explore (); From d95b4befaa66b8047398075391e3591b1e2a9e84 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 04:09:55 +0100 Subject: [PATCH 33/46] Adding support for config file Example: -port=17070 --port=17070 cat /home/$USER/.i2pd/i2p.conf port=17070 --- Makefile | 2 +- i2p.cpp | 21 +++++- util.cpp | 214 +++++++++++++++++++++++++++++++++++++++++++------------ util.h | 24 +++++-- 4 files changed, 206 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index 240e4a3b..b5739c46 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transpor obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \ obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o INCFLAGS = -LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lpthread +LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LIBS = all: obj i2p diff --git a/i2p.cpp b/i2p.cpp index 5c0bd378..82a69671 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "Log.h" #include "base64.h" #include "Transports.h" @@ -14,7 +15,7 @@ int main( int argc, char* argv[] ) { - i2p::util::OptionParser(argc,argv); + i2p::util::config::OptionParser(argc,argv); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); @@ -22,10 +23,24 @@ int main( int argc, char* argv[] ) setlocale(LC_ALL, "Russian"); #endif + LogPrint("\n\n\n\ni2pd starting\n"); + LogPrint("default data directory: ", i2p::util::filesystem::GetDefaultDataDir().string()); + if (!boost::filesystem::exists( i2p::util::filesystem::GetDefaultDataDir() )) + { + // Create data directory + if (!boost::filesystem::create_directory( i2p::util::filesystem::GetDefaultDataDir() )) + { + LogPrint("Failed to create data directory, exiting! :("); + return -1; + } + } + i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); + //TODO: This is an ugly workaround. fix it. //TODO: Autodetect public IP. - i2p::context.OverrideNTCPAddress(i2p::util::GetCharArg("--host", "127.0.0.1"), i2p::util::GetIntArg("--port", 17070)); - int httpport = i2p::util::GetIntArg("--httpport", 7070); + i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), + i2p::util::config::GetArg("-port", 17070)); + int httpport = i2p::util::config::GetArg("-httpport", 7070); i2p::util::HTTPServer httpServer (httpport); diff --git a/util.cpp b/util.cpp index a33414ac..ff013035 100644 --- a/util.cpp +++ b/util.cpp @@ -3,7 +3,13 @@ #include #include #include +#include #include +#include +#include +#include +#include +#include #include "util.h" #include "Log.h" @@ -11,40 +17,154 @@ namespace i2p { namespace util { -std::map mapArgs; -void OptionParser(int argc, const char* const argv[]) +namespace config { - mapArgs.clear(); - for (int i = 1; i < argc; i++) - { - std::string strKey (argv[i]); - std::string strValue; - size_t has_data = strKey.find('='); - if (has_data != std::string::npos) - { - strValue = strKey.substr(has_data+1); - strKey = strKey.substr(0, has_data); - } - if (strKey[0] != '-') - break; + std::map mapArgs; + std::map > mapMultiArgs; - mapArgs[strKey] = strValue; - } + void OptionParser(int argc, const char* const argv[]) + { + mapArgs.clear(); + mapMultiArgs.clear(); + for (int i = 1; i < argc; i++) + { + std::string strKey (argv[i]); + std::string strValue; + size_t has_data = strKey.find('='); + if (has_data != std::string::npos) + { + strValue = strKey.substr(has_data+1); + strKey = strKey.substr(0, has_data); + } + +#ifdef WIN32 + boost::to_lower(strKey); + if (boost::algorithm::starts_with(strKey, "/")) + strKey = "-" + strKey.substr(1); +#endif + if (strKey[0] != '-') + break; + + mapArgs[strKey] = strValue; + mapMultiArgs[strKey].push_back(strValue); + } + + BOOST_FOREACH(PAIRTYPE(const std::string,std::string)& entry, mapArgs) + { + std::string name = entry.first; + + // interpret --foo as -foo (as long as both are not set) + if (name.find("--") == 0) + { + std::string singleDash(name.begin()+1, name.end()); + if (mapArgs.count(singleDash) == 0) + mapArgs[singleDash] = entry.second; + name = singleDash; + } + } + } + + const char* GetCharArg(const std::string& strArg, const std::string& nDefault) + { + if (mapArgs.count(strArg)) + return mapArgs[strArg].c_str(); + return nDefault.c_str(); + } + + std::string GetArg(const std::string& strArg, const std::string& strDefault) + { + if (mapArgs.count(strArg)) + return mapArgs[strArg]; + return strDefault; + } + + int GetArg(const std::string& strArg, int nDefault) + { + if (mapArgs.count(strArg)) + return atoi(mapArgs[strArg].c_str()); + return nDefault; + } } -int GetIntArg(const std::string& strArg, int nDefault) +namespace filesystem { - if (mapArgs.count(strArg)) - return atoi(mapArgs[strArg].c_str()); - return nDefault; -} + const boost::filesystem::path &GetDataDir(bool fNetSpecific) + { -const char* GetCharArg(const std::string& strArg, const std::string& nDefault) -{ - if (mapArgs.count(strArg)) - return mapArgs[strArg].c_str(); - return nDefault.c_str(); + static boost::filesystem::path path; + + if (config::mapArgs.count("--datadir")) { + path = boost::filesystem::system_complete(config::mapArgs["--datadir"]); + if (!boost::filesystem::is_directory(path)) { + path = ""; + return path; + } + } else { + path = GetDefaultDataDir(); + } + + boost::filesystem::create_directory(path); + + return path; + } + + boost::filesystem::path GetConfigFile() + { + boost::filesystem::path pathConfigFile(i2p::util::config::GetArg("-conf", "i2p.conf")); + if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile; + return pathConfigFile; + } + + void ReadConfigFile(std::map& mapSettingsRet, + std::map >& mapMultiSettingsRet) + { + boost::filesystem::ifstream streamConfig(GetConfigFile()); + if (!streamConfig.good()) + return; // No i2pd.conf file is OK + + std::set setOptions; + setOptions.insert("*"); + + for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) + { + // Don't overwrite existing settings so command line settings override i2pd.conf + std::string strKey = std::string("-") + it->string_key; + if (mapSettingsRet.count(strKey) == 0) + { + mapSettingsRet[strKey] = it->value[0]; + } + mapMultiSettingsRet[strKey].push_back(it->value[0]); + } + } + + boost::filesystem::path GetDefaultDataDir() + { + // Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd + // Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd + // Mac: ~/Library/Application Support/i2pd + // Unix: ~/.i2pd +#ifdef WIN32 + // Windows + return GetSpecialFolderPath(CSIDL_APPDATA) / "i2pd"; +#else + boost::filesystem::path pathRet; + char* pszHome = getenv("HOME"); + if (pszHome == NULL || strlen(pszHome) == 0) + pathRet = boost::filesystem::path("/"); + else + pathRet = boost::filesystem::path(pszHome); +#ifdef MAC_OSX + // Mac + pathRet /= "Library/Application Support"; + boost::filesystem::create_directory(pathRet); + return pathRet / "i2pd"; +#else + // Unix + return pathRet / ".i2pd"; +#endif +#endif + } } namespace http @@ -102,26 +222,26 @@ namespace http void url::parse(const std::string& url_s) { - const std::string prot_end("://"); - std::string::const_iterator prot_i = search(url_s.begin(), url_s.end(), - prot_end.begin(), prot_end.end()); - protocol_.reserve(distance(url_s.begin(), prot_i)); - transform(url_s.begin(), prot_i, - back_inserter(protocol_), - std::ptr_fun(tolower)); // protocol is icase - if( prot_i == url_s.end() ) - return; - advance(prot_i, prot_end.length()); - std::string::const_iterator path_i = find(prot_i, url_s.end(), '/'); - host_.reserve(distance(prot_i, path_i)); - transform(prot_i, path_i, - back_inserter(host_), - std::ptr_fun(tolower)); // host is icase - std::string::const_iterator query_i = find(path_i, url_s.end(), '?'); - path_.assign(path_i, query_i); - if( query_i != url_s.end() ) - ++query_i; - query_.assign(query_i, url_s.end()); + const std::string prot_end("://"); + std::string::const_iterator prot_i = search(url_s.begin(), url_s.end(), + prot_end.begin(), prot_end.end()); + protocol_.reserve(distance(url_s.begin(), prot_i)); + transform(url_s.begin(), prot_i, + back_inserter(protocol_), + std::ptr_fun(tolower)); // protocol is icase + if( prot_i == url_s.end() ) + return; + advance(prot_i, prot_end.length()); + std::string::const_iterator path_i = find(prot_i, url_s.end(), '/'); + host_.reserve(distance(prot_i, path_i)); + transform(prot_i, path_i, + back_inserter(host_), + std::ptr_fun(tolower)); // host is icase + std::string::const_iterator query_i = find(path_i, url_s.end(), '?'); + path_.assign(path_i, query_i); + if( query_i != url_s.end() ) + ++query_i; + query_.assign(query_i, url_s.end()); } } diff --git a/util.h b/util.h index 7643e0d0..7f22e3f1 100644 --- a/util.h +++ b/util.h @@ -4,14 +4,30 @@ #include #include +#define PAIRTYPE(t1, t2) std::pair + namespace i2p { namespace util { - extern std::map mapArgs; - void OptionParser(int argc, const char* const argv[]); - int GetIntArg(const std::string& strArg, int nDefault); - const char* GetCharArg(const std::string& strArg, const std::string& nDefault); + namespace config + { + extern std::map mapArgs; + extern std::map > mapMultiArgs; + void OptionParser(int argc, const char* const argv[]); + int GetArg(const std::string& strArg, int nDefault); + std::string GetArg(const std::string& strArg, const std::string& strDefault); + const char* GetCharArg(const std::string& strArg, const std::string& nDefault); + } + + namespace filesystem + { + boost::filesystem::path GetDefaultDataDir(); + boost::filesystem::path GetConfigFile(); + void ReadConfigFile(std::map& mapSettingsRet, + std::map >& mapMultiSettingsRet); + } + namespace http { std::string httpRequest(const std::string& address); From 56f1f627ef8af1ba1592561ae42abba68d090c0f Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 04:15:19 +0100 Subject: [PATCH 34/46] use single dash to query options --- util.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util.cpp b/util.cpp index ff013035..2da8fdb5 100644 --- a/util.cpp +++ b/util.cpp @@ -94,8 +94,8 @@ namespace filesystem static boost::filesystem::path path; - if (config::mapArgs.count("--datadir")) { - path = boost::filesystem::system_complete(config::mapArgs["--datadir"]); + if (config::mapArgs.count("-datadir")) { + path = boost::filesystem::system_complete(config::mapArgs["-datadir"]); if (!boost::filesystem::is_directory(path)) { path = ""; return path; From 2fd31c6c8d77637a828c09b2d0ac3e9ba3ccbfa6 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 04:51:58 +0100 Subject: [PATCH 35/46] Custom datadir + cleanup --- i2p.cpp | 11 +---------- util.cpp | 27 +++++++++++++++++---------- util.h | 1 + 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/i2p.cpp b/i2p.cpp index 82a69671..aed38cd0 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -24,16 +24,7 @@ int main( int argc, char* argv[] ) #endif LogPrint("\n\n\n\ni2pd starting\n"); - LogPrint("default data directory: ", i2p::util::filesystem::GetDefaultDataDir().string()); - if (!boost::filesystem::exists( i2p::util::filesystem::GetDefaultDataDir() )) - { - // Create data directory - if (!boost::filesystem::create_directory( i2p::util::filesystem::GetDefaultDataDir() )) - { - LogPrint("Failed to create data directory, exiting! :("); - return -1; - } - } + LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string()); i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); //TODO: This is an ugly workaround. fix it. diff --git a/util.cpp b/util.cpp index 2da8fdb5..1c64cc75 100644 --- a/util.cpp +++ b/util.cpp @@ -89,30 +89,37 @@ namespace config namespace filesystem { - const boost::filesystem::path &GetDataDir(bool fNetSpecific) + const boost::filesystem::path &GetDataDir() { static boost::filesystem::path path; - if (config::mapArgs.count("-datadir")) { - path = boost::filesystem::system_complete(config::mapArgs["-datadir"]); - if (!boost::filesystem::is_directory(path)) { - path = ""; - return path; - } + if (i2p::util::config::mapArgs.count("-datadir")) { + path = boost::filesystem::system_complete(i2p::util::config::mapArgs["-datadir"]); } else { path = GetDefaultDataDir(); } - boost::filesystem::create_directory(path); - + if (!boost::filesystem::exists( path )) + { + // Create data directory + if (!boost::filesystem::create_directory( path )) + { + LogPrint("Failed to create data directory!"); + return ""; + } + } + if (!boost::filesystem::is_directory(path)) { + path = GetDefaultDataDir(); + } + LogPrint("Debug: ",path.string()); return path; } boost::filesystem::path GetConfigFile() { boost::filesystem::path pathConfigFile(i2p::util::config::GetArg("-conf", "i2p.conf")); - if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile; + if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir() / pathConfigFile; return pathConfigFile; } diff --git a/util.h b/util.h index 7f22e3f1..7090294f 100644 --- a/util.h +++ b/util.h @@ -22,6 +22,7 @@ namespace util namespace filesystem { + const boost::filesystem::path &GetDataDir(); boost::filesystem::path GetDefaultDataDir(); boost::filesystem::path GetConfigFile(); void ReadConfigFile(std::map& mapSettingsRet, From ef9801f704ce012cdfacf00a3175dc87cc649a77 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 05:25:59 +0100 Subject: [PATCH 36/46] Remove debug --- util.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/util.cpp b/util.cpp index 1c64cc75..e988427c 100644 --- a/util.cpp +++ b/util.cpp @@ -112,7 +112,6 @@ namespace filesystem if (!boost::filesystem::is_directory(path)) { path = GetDefaultDataDir(); } - LogPrint("Debug: ",path.string()); return path; } From f639f971b2d673a367cdb3ff27624899b8bffef2 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 14:28:30 +0100 Subject: [PATCH 37/46] Should fix compilation error on some systems --- util.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util.h b/util.h index 7090294f..519e51b3 100644 --- a/util.h +++ b/util.h @@ -3,6 +3,8 @@ #include #include +#include +#include #define PAIRTYPE(t1, t2) std::pair From bf2e8d23507266e4612edb755a0f310aada83ec3 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Feb 2014 09:06:28 -0500 Subject: [PATCH 38/46] fixed HMAC calculation. Tested and verified --- hmac.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hmac.h b/hmac.h index df35a142..6e9c042b 100644 --- a/hmac.h +++ b/hmac.h @@ -18,7 +18,6 @@ namespace crypto // digest is 16 bytes // block size is 64 bytes { - size_t totalLen = len + 64 + 32; uint8_t buf[2048]; // ikeypad ((uint64_t *)buf)[0] = ((uint64_t *)key)[0] ^ IPAD; @@ -47,10 +46,10 @@ namespace crypto // copy first hash after okeypad memcpy (buf + 64, hash, 16); // fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P) - memset (buf + 72, 0, 16); + memset (buf + 80, 0, 16); // calculate digest - CryptoPP::Weak1::MD5().CalculateDigest (digest, buf, totalLen); + CryptoPP::Weak1::MD5().CalculateDigest (digest, buf, 96); } } } From ca1e1c48967a991c276cff32634c817c25be7764 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Feb 2014 09:16:50 -0500 Subject: [PATCH 39/46] fixed compilation error and potentil memory corruption --- util.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/util.cpp b/util.cpp index e988427c..88a1f7c8 100644 --- a/util.cpp +++ b/util.cpp @@ -91,7 +91,6 @@ namespace filesystem { const boost::filesystem::path &GetDataDir() { - static boost::filesystem::path path; if (i2p::util::config::mapArgs.count("-datadir")) { @@ -106,7 +105,8 @@ namespace filesystem if (!boost::filesystem::create_directory( path )) { LogPrint("Failed to create data directory!"); - return ""; + path = ""; + return path; } } if (!boost::filesystem::is_directory(path)) { @@ -181,7 +181,9 @@ namespace http { i2p::util::http::url u(address); boost::asio::ip::tcp::iostream site; - site.expires_from_now (boost::posix_time::seconds(30)); + // please don't uncomment following line because it's not compatible with boost 1.46 + // 1.46 is default boost for Ubuntu 12.04 LTS + //site.expires_from_now (boost::posix_time::seconds(30)); site.connect(u.host_, "http"); if (site) { From d87a79b226801eb4758be60ab06d1612860285a9 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sat, 1 Feb 2014 16:10:15 +0100 Subject: [PATCH 40/46] Load netDb from data directory --- NetDb.cpp | 29 +++++++++++++++++++---------- NetDb.h | 2 +- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 49c37562..41aa7c4f 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -14,6 +14,7 @@ #include "Garlic.h" #include "NetDb.h" #include "Reseed.h" +#include "util.h" namespace i2p { @@ -62,13 +63,21 @@ namespace data void NetDb::Start () { - Load ("netDb"); +#ifndef _WIN32 + Load ("/netDb"); +#else + Load ("\\netDb"); +#endif while (m_RouterInfos.size () < 100 && m_ReseedRetries < 10) { Reseeder reseeder; reseeder.reseedNow(); m_ReseedRetries++; - Load ("netDb"); +#ifndef _WIN32 + Load ("/netDb"); +#else + Load ("\\netDb"); +#endif } m_Thread = new std::thread (std::bind (&NetDb::Run, this)); } @@ -188,13 +197,12 @@ namespace data } // TODO: Move to reseed and/or scheduled tasks. (In java version, scheduler fix this as well as sort RIs.) - bool NetDb::CreateNetDb(const char * directory) + bool NetDb::CreateNetDb(boost::filesystem::path directory) { - boost::filesystem::path p (directory); - LogPrint (directory, " doesn't exist, trying to create it."); - if (!boost::filesystem::create_directory (p)) + LogPrint (directory.string(), " doesn't exist, trying to create it."); + if (!boost::filesystem::create_directory (directory)) { - LogPrint("Failed to create directory ", directory); + LogPrint("Failed to create directory ", directory.string()); return false; } @@ -208,18 +216,19 @@ namespace data #else suffix = std::string ("\\r") + chars[i]; #endif - if (!boost::filesystem::create_directory( boost::filesystem::path (p / suffix) )) return false; + if (!boost::filesystem::create_directory( boost::filesystem::path (directory / suffix) )) return false; } return true; } void NetDb::Load (const char * directory) { - boost::filesystem::path p (directory); + boost::filesystem::path p (i2p::util::filesystem::GetDataDir()); + p /= (directory); if (!boost::filesystem::exists (p)) { // seems netDb doesn't exist yet - if (!CreateNetDb(directory)) return; + if (!CreateNetDb(p)) return; } // make sure we cleanup netDb from previous attempts for (auto r: m_RouterInfos) diff --git a/NetDb.h b/NetDb.h index 3fb6ad10..7988276a 100644 --- a/NetDb.h +++ b/NetDb.h @@ -76,7 +76,7 @@ namespace data private: - bool CreateNetDb(const char * directory); + bool CreateNetDb(boost::filesystem::path directory); void Load (const char * directory); void SaveUpdated (const char * directory); void Run (); // exploratory thread From 8963c0b3090837fdfae6e4600860f525d908861b Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Feb 2014 15:57:46 -0500 Subject: [PATCH 41/46] save new RouterInfos to ~/.i2pd --- NetDb.cpp | 40 +++++++++++++++++++++------------------- NetDb.h | 3 +++ 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 41aa7c4f..01234ad7 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include "base64.h" #include "Log.h" @@ -20,7 +19,6 @@ namespace i2p { namespace data { - I2NPMessage * RequestedDestination::CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel) { @@ -43,7 +41,12 @@ namespace data m_LastReplyTunnel = nullptr; return msg; } - + +#ifndef _WIN32 + const char NetDb::m_NetDbPath[] = "/netDb"; +#else + const char NetDb::m_NetDbPath[] = "\\netDb"; +#endif NetDb netdb; NetDb::NetDb (): m_IsRunning (false), m_ReseedRetries (0), m_Thread (0) @@ -62,22 +65,14 @@ namespace data } void NetDb::Start () - { -#ifndef _WIN32 - Load ("/netDb"); -#else - Load ("\\netDb"); -#endif + { + Load (m_NetDbPath); while (m_RouterInfos.size () < 100 && m_ReseedRetries < 10) { Reseeder reseeder; reseeder.reseedNow(); m_ReseedRetries++; -#ifndef _WIN32 - Load ("/netDb"); -#else - Load ("\\netDb"); -#endif + Load (m_NetDbPath); } m_Thread = new std::thread (std::bind (&NetDb::Run, this)); } @@ -128,7 +123,7 @@ namespace data if (ts - lastTs >= 60) // save routers every minute { if (lastTs) - SaveUpdated ("netDb"); + SaveUpdated (m_NetDbPath); lastTs = ts; } } @@ -270,7 +265,14 @@ namespace data #endif routerInfo->GetIdentHashBase64 () + ".dat"; }; - + + boost::filesystem::path p (i2p::util::filesystem::GetDataDir()); + p /= (directory); +#if BOOST_VERSION > 10500 + const char * fullDirectory = p.string().c_str (); +#else + const char * fullDirectory = p.c_str (); +#endif int count = 0, deletedCount = 0; auto total = m_RouterInfos.size (); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); @@ -278,7 +280,7 @@ namespace data { if (it.second->IsUpdated ()) { - std::ofstream r (GetFilePath(directory, it.second), std::ofstream::binary); + std::ofstream r (GetFilePath(fullDirectory, it.second), std::ofstream::binary); r.write ((char *)it.second->GetBuffer (), it.second->GetBufferLen ()); it.second->SetUpdated (false); count++; @@ -294,9 +296,9 @@ namespace data if (it.second->IsUnreachable ()) { - if (boost::filesystem::exists (GetFilePath (directory, it.second))) + if (boost::filesystem::exists (GetFilePath (fullDirectory, it.second))) { - boost::filesystem::remove (GetFilePath (directory, it.second)); + boost::filesystem::remove (GetFilePath (fullDirectory, it.second)); deletedCount++; } } diff --git a/NetDb.h b/NetDb.h index 7988276a..bcf1f23c 100644 --- a/NetDb.h +++ b/NetDb.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "Queue.h" #include "I2NPProtocol.h" #include "RouterInfo.h" @@ -97,6 +98,8 @@ namespace data int m_ReseedRetries; std::thread * m_Thread; i2p::util::Queue m_Queue; // of I2NPDatabaseStoreMsg + + static const char m_NetDbPath[]; }; extern NetDb netdb; From 499a7a9e32baffe65437ded19a0d07543669bbc5 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Feb 2014 18:46:28 -0500 Subject: [PATCH 42/46] use key of remote router as ident key for SessionCreated --- SSU.cpp | 30 +++++++++++++++++++++--------- SSU.h | 2 +- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 1c7d0155..94dbcfb7 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -59,7 +59,9 @@ namespace ssu void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { LogPrint ("Process session request"); - if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, buf, len)) + // use our intro key + if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, + i2p::context.GetRouterInfo (), buf, len)) { m_State = eSessionStateRequestReceived; LogPrint ("Session request received"); @@ -71,11 +73,20 @@ namespace ssu void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len) { LogPrint ("Process session created"); - if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, buf, len)) + if (!m_RemoteRouter) + { + LogPrint ("Unsolicited session created message"); + return; + } + + // use remote intro key + if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, *m_RemoteRouter, buf, len)) { m_State = eSessionStateCreatedReceived; - LogPrint ("Session request received"); - // TODO: + LogPrint ("Session created received"); + boost::asio::ip::address_v4 ourAddress (be32toh (*(uint32_t* )(buf + sizeof (SSUHeader) + 257))); + uint16_t ourPort = be16toh (*(uint16_t *)(buf + sizeof (SSUHeader) + 261)); + LogPrint ("Our external address is ", ourAddress.to_string (), ":", ourPort); } } @@ -92,7 +103,7 @@ namespace ssu uint8_t * payload = buf + sizeof (SSUHeader); memcpy (payload, i2p::context.GetRouterIdentity ().publicKey, 256); payload[256] = 4; // we assume ipv4 - *(uint32_t *)(payload + 257) = address->host.to_v4 ().to_ulong (); // network bytes order already + *(uint32_t *)(payload + 257) = htobe32 (address->host.to_v4 ().to_ulong ()); uint8_t iv[16]; CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); @@ -121,7 +132,7 @@ namespace ssu payload += 256; *payload = 4; // we assume ipv4 payload++; - *(uint32_t *)(payload) = m_RemoteEndpoint.address ().to_v4 ().to_ulong (); // network bytes order already + *(uint32_t *)(payload) = htobe32 (m_RemoteEndpoint.address ().to_v4 ().to_ulong ()); payload += 4; *(uint16_t *)(payload) = htobe16 (m_RemoteEndpoint.port ()); payload += 2; @@ -149,9 +160,9 @@ namespace ssu m_Server->Send (buf, 368, m_RemoteEndpoint); } - bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len) + bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len) { - auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); + auto address = r.GetSSUAddress (); if (address) { // use intro key for verification and decryption @@ -171,7 +182,7 @@ namespace ssu LogPrint ("MAC verifcation failed"); } else - LogPrint ("SSU is not supported"); + LogPrint ("SSU is not supported by ", r.GetIdentHashAbbreviation ()); return false; } @@ -207,6 +218,7 @@ namespace ssu uint8_t * encrypted = &header->flag; uint16_t encryptedLen = len - (encrypted - buf); m_Decryption.SetKeyWithIV (aesKey, 32, header->iv); + encryptedLen = (encryptedLen/16)*16; // make sure 16 bytes boundary m_Decryption.ProcessData (encrypted, encrypted, encryptedLen); } diff --git a/SSU.h b/SSU.h index 6b2d108a..1dcf536e 100644 --- a/SSU.h +++ b/SSU.h @@ -70,7 +70,7 @@ namespace ssu void ProcessSessionCreated (uint8_t * buf, size_t len); void SendSessionCreated (const uint8_t * x); - bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len); + bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len); void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); void Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey); bool Validate (uint8_t * buf, size_t len, uint8_t * macKey); From 04cf2031ef0d0b659773812475510db494e43215 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 1 Feb 2014 22:20:41 -0500 Subject: [PATCH 43/46] handle received packets in right order --- Streaming.cpp | 90 ++++++++++++++++++++++++++------------------------- Streaming.h | 1 + 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/Streaming.cpp b/Streaming.cpp index 86f2a55c..f73c5125 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -34,55 +34,22 @@ namespace stream if (!m_SendStreamID) m_SendStreamID = packet->GetReceiveStreamID (); - // process flags - uint16_t flags = packet->GetFlags (); - const uint8_t * optionData = packet->GetOptionData (); - if (flags & PACKET_FLAG_SYNCHRONIZE) - { - LogPrint ("Synchronize"); - } - - if (flags & PACKET_FLAG_SIGNATURE_INCLUDED) - { - LogPrint ("Signature"); - optionData += 40; - } - - if (flags & PACKET_FLAG_FROM_INCLUDED) - { - LogPrint ("From identity"); - optionData += sizeof (i2p::data::Identity); - } - uint32_t receivedSeqn = packet->GetSeqn (); - LogPrint ("seqn=", receivedSeqn, ", flags=", flags); + LogPrint ("Received seqn=", receivedSeqn); if (!receivedSeqn || receivedSeqn == m_LastReceivedSequenceNumber + 1) { - // we have received next message - packet->offset = packet->GetPayload () - packet->buf; - if (packet->GetLength () > 0) - m_ReceiveQueue.Put (packet); - else - delete packet; - - m_LastReceivedSequenceNumber = receivedSeqn; - SendQuickAck (); + // we have received next in sequence message + ProcessPacket (packet); // we should also try stored messages if any for (auto it = m_SavedPackets.begin (); it != m_SavedPackets.end ();) { if ((*it)->GetSeqn () == m_LastReceivedSequenceNumber + 1) { - Packet * packet = *it; + Packet * savedPacket = *it; m_SavedPackets.erase (it++); - LogPrint ("Process saved packet seqn=", packet->GetSeqn ()); - if (packet->GetLength () > 0) - m_ReceiveQueue.Put (packet); - else - delete packet; - m_LastReceivedSequenceNumber++; - SendQuickAck (); + ProcessPacket (savedPacket); } else break; @@ -106,7 +73,47 @@ namespace stream SavePacket (packet); } } - + } + + void Stream::SavePacket (Packet * packet) + { + m_SavedPackets.insert (packet); + } + + void Stream::ProcessPacket (Packet * packet) + { + // process flags + uint32_t receivedSeqn = packet->GetSeqn (); + uint16_t flags = packet->GetFlags (); + LogPrint ("Process seqn=", receivedSeqn, ", flags=", flags); + + const uint8_t * optionData = packet->GetOptionData (); + if (flags & PACKET_FLAG_SYNCHRONIZE) + { + LogPrint ("Synchronize"); + } + + if (flags & PACKET_FLAG_SIGNATURE_INCLUDED) + { + LogPrint ("Signature"); + optionData += 40; + } + + if (flags & PACKET_FLAG_FROM_INCLUDED) + { + LogPrint ("From identity"); + optionData += sizeof (i2p::data::Identity); + } + + packet->offset = packet->GetPayload () - packet->buf; + if (packet->GetLength () > 0) + m_ReceiveQueue.Put (packet); + else + delete packet; + + m_LastReceivedSequenceNumber = receivedSeqn; + SendQuickAck (); + if (flags & PACKET_FLAG_CLOSE) { LogPrint ("Closed"); @@ -114,11 +121,6 @@ namespace stream m_ReceiveQueue.WakeUp (); } } - - void Stream::SavePacket (Packet * packet) - { - m_SavedPackets.insert (packet); - } size_t Stream::Send (uint8_t * buf, size_t len, int timeout) { diff --git a/Streaming.h b/Streaming.h index 5939d058..18d09b5d 100644 --- a/Streaming.h +++ b/Streaming.h @@ -84,6 +84,7 @@ namespace stream void SendQuickAck (); void SavePacket (Packet * packet); + void ProcessPacket (Packet * packet); private: From 11e11df5ca1453fd819edc6fb811727f13991436 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sun, 2 Feb 2014 20:37:43 +0100 Subject: [PATCH 44/46] Fixing reseed --- Reseed.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Reseed.cpp b/Reseed.cpp index 540caa15..e60ffa44 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "Reseed.h" #include "Log.h" #include "util.h" @@ -56,6 +57,7 @@ namespace data std::string tmpUrl; std::string filename; std::string ignoreFileSuffix = ".zip"; + boost::filesystem::path root = i2p::util::filesystem::GetDataDir(); while (i != j) { name = *i++; @@ -65,9 +67,20 @@ namespace data tmpUrl = reseedHost; tmpUrl.append(name); routerInfo = i2p::util::http::httpRequest(tmpUrl); - filename = "netDb/r"; + if (routerInfo.size()==0) + continue; + filename = root.string(); +#ifndef _WIN32 + filename += "/netDb/r"; +#else + filename += "\\netDb\\r"; +#endif filename += name.at(11); // first char in id +#ifndef _WIN32 filename.append("/"); +#else + filename.append("\\"); +#endif filename.append(name.c_str()); std::ofstream outfile (filename, std::ios::binary); outfile << routerInfo; From a46f311762825197cfa2f1764e58de0e0e7188e5 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sun, 2 Feb 2014 23:22:00 +0100 Subject: [PATCH 45/46] RouterInfo file size fix --- RouterInfo.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 44bd90e4..1d6eb6d5 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -46,7 +46,11 @@ namespace data if (s.is_open ()) { s.seekg (0,std::ios::end); - m_BufferLen = s.tellg (); + m_BufferLen = s.tellg (); + if (m_BufferLen < 40) + { + LogPrint("File", filename, " is malformed"); + } s.seekg(0, std::ios::beg); s.read(m_Buffer,m_BufferLen); ReadFromBuffer (); From 1efe9cc41ecfa5d3075091c283bf9b1c58e706b2 Mon Sep 17 00:00:00 2001 From: Meeh Date: Sun, 2 Feb 2014 23:23:15 +0100 Subject: [PATCH 46/46] return --- RouterInfo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 1d6eb6d5..3b0054a0 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -50,6 +50,7 @@ namespace data if (m_BufferLen < 40) { LogPrint("File", filename, " is malformed"); + return; } s.seekg(0, std::ios::beg); s.read(m_Buffer,m_BufferLen);