From 2d428fd090fd581601e8bb7fdd774bb29d079532 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2014 16:07:16 -0500 Subject: [PATCH 01/38] use boost::asio::address for address --- NTCPSession.cpp | 4 ++-- NTCPSession.h | 2 +- RouterContext.cpp | 4 ++-- RouterInfo.cpp | 6 +++--- RouterInfo.h | 2 +- Transports.cpp | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 61e7944f..061dbbac 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -517,10 +517,10 @@ namespace ntcp } - NTCPClient::NTCPClient (boost::asio::io_service& service, const char * address, + NTCPClient::NTCPClient (boost::asio::io_service& service, boost::asio::ip::address& address, int port, i2p::data::RouterInfo& in_RouterInfo): NTCPSession (service, in_RouterInfo), - m_Endpoint (boost::asio::ip::address::from_string (address), port) + m_Endpoint (address, port) { Connect (); } diff --git a/NTCPSession.h b/NTCPSession.h index 5d33ef10..512d65ec 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -144,7 +144,7 @@ namespace ntcp { public: - NTCPClient (boost::asio::io_service& service, const char * address, int port, i2p::data::RouterInfo& in_RouterInfo); + NTCPClient (boost::asio::io_service& service, boost::asio::ip::address& address, int port, i2p::data::RouterInfo& in_RouterInfo); private: diff --git a/RouterContext.cpp b/RouterContext.cpp index 718a9f36..3e19c810 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -45,7 +45,7 @@ namespace i2p auto address = m_RouterInfo.GetNTCPAddress (); if (address) { - address->host = host; + address->host = boost::asio::ip::address::from_string (host); address->port = port; } @@ -80,4 +80,4 @@ namespace i2p std::ofstream fi (ROUTER_INFO); fi.write ((char *)m_RouterInfo.GetBuffer (), m_RouterInfo.GetBufferLen ()); } -} \ No newline at end of file +} diff --git a/RouterInfo.cpp b/RouterInfo.cpp index d804ecad..5125bfa9 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -101,7 +101,7 @@ namespace data r += ReadString (value, s); s.seekg (1, std::ios_base::cur); r++; // ; if (!strcmp (key, "host")) - address.host = value; + address.host = boost::asio::ip::address::from_string (value); else if (!strcmp (key, "port")) address.port = boost::lexical_cast(value); } @@ -166,7 +166,7 @@ namespace data std::stringstream properties; WriteString ("host", properties); properties << '='; - WriteString (address.host, properties); + WriteString (address.host.to_string (), properties); properties << ';'; WriteString ("port", properties); properties << '='; @@ -227,7 +227,7 @@ namespace data void RouterInfo::AddNTCPAddress (const char * host, int port) { Address addr; - addr.host = host; + addr.host = boost::asio::ip::address::from_string (host); addr.port = port; addr.transportStyle = eTransportNTCP; addr.cost = 2; diff --git a/RouterInfo.h b/RouterInfo.h index a8d59adf..09440946 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -27,7 +27,7 @@ namespace data struct Address { TransportStyle transportStyle; - std::string host; + boost::asio::ip::address host; int port; uint64_t date; uint8_t cost; diff --git a/Transports.cpp b/Transports.cpp index 371ea2e6..31d0325f 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -139,7 +139,7 @@ namespace i2p auto address = r->GetNTCPAddress (); if (address) { - session = new i2p::ntcp::NTCPClient (m_Service, address->host.c_str (), address->port, *r); + session = new i2p::ntcp::NTCPClient (m_Service, address->host, address->port, *r); AddNTCPSession (session); } else From ddb9a6b4772c8f7c039791e2f46697fdddff5b83 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2014 18:01:11 -0500 Subject: [PATCH 02/38] check if IP address is valid --- NTCPSession.cpp | 2 +- NTCPSession.h | 2 +- RouterInfo.cpp | 11 ++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 061dbbac..3e3d551d 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -517,7 +517,7 @@ namespace ntcp } - NTCPClient::NTCPClient (boost::asio::io_service& service, boost::asio::ip::address& address, + NTCPClient::NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, i2p::data::RouterInfo& in_RouterInfo): NTCPSession (service, in_RouterInfo), m_Endpoint (address, port) diff --git a/NTCPSession.h b/NTCPSession.h index 512d65ec..71cf5af9 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -144,7 +144,7 @@ namespace ntcp { public: - NTCPClient (boost::asio::io_service& service, boost::asio::ip::address& address, int port, i2p::data::RouterInfo& in_RouterInfo); + NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, i2p::data::RouterInfo& in_RouterInfo); private: diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 5125bfa9..c630fac5 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -101,7 +101,16 @@ namespace data r += ReadString (value, s); s.seekg (1, std::ios_base::cur); r++; // ; if (!strcmp (key, "host")) - address.host = boost::asio::ip::address::from_string (value); + { + boost::system::error_code ecode; + address.host = boost::asio::ip::address::from_string (value, ecode); + if (ecode) + { + // TODO: we should try to resolve address here + LogPrint ("Unexpected address ", value); + SetUnreachable (true); + } + } else if (!strcmp (key, "port")) address.port = boost::lexical_cast(value); } From fcad81907471bc83b12e7da30644379e0fb210ab Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2014 19:14:30 -0500 Subject: [PATCH 03/38] ipv4 only --- RouterInfo.cpp | 14 ++++++++++---- RouterInfo.h | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index c630fac5..5c2eecef 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -265,22 +265,28 @@ namespace data return false; } - bool RouterInfo::IsNTCP () const + bool RouterInfo::IsNTCP (bool v4only) const { for (auto& address : m_Addresses) { if (address.transportStyle == eTransportNTCP) - return true; + { + if (!v4only || address.host.is_v4 ()) + return true; + } } return false; } - RouterInfo::Address * RouterInfo::GetNTCPAddress () + RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) { for (auto& address : m_Addresses) { if (address.transportStyle == eTransportNTCP) - return &address; + { + if (!v4only || address.host.is_v4 ()) + return &address; + } } return nullptr; } diff --git a/RouterInfo.h b/RouterInfo.h index 09440946..44dae3f1 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -45,14 +45,14 @@ namespace data const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; }; uint64_t GetTimestamp () const { return m_Timestamp; }; const std::vector
& GetAddresses () const { return m_Addresses; }; - Address * GetNTCPAddress (); + Address * GetNTCPAddress (bool v4only = true); const RoutingKey& GetRoutingKey () const { return m_RoutingKey; }; void AddNTCPAddress (const char * host, int port); void SetProperty (const char * key, const char * value); const char * GetProperty (const char * key) const; bool IsFloodfill () const; - bool IsNTCP () const; + bool IsNTCP (bool v4only = true) const; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; bool IsUnreachable () const { return m_IsUnreachable; }; From 7d2281b4773e9e7d391e62e427a1546b3454037e Mon Sep 17 00:00:00 2001 From: chertov Date: Wed, 22 Jan 2014 06:02:22 +0400 Subject: [PATCH 04/38] fix binary files --- RouterContext.cpp | 6 +++--- RouterInfo.cpp | 16 +++++++++++++--- TunnelConfig.h | 3 ++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/RouterContext.cpp b/RouterContext.cpp index 718a9f36..d3e1def1 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -60,7 +60,7 @@ namespace i2p bool RouterContext::Load () { - std::ifstream fk (ROUTER_KEYS); + std::ifstream fk (ROUTER_KEYS, std::ios::binary); if (!fk.is_open ()) return false; fk.read ((char *)&m_Keys, sizeof (m_Keys)); @@ -74,10 +74,10 @@ namespace i2p void RouterContext::Save () { - std::ofstream fk (ROUTER_KEYS); + std::ofstream fk (ROUTER_KEYS, std::ios::binary); fk.write ((char *)&m_Keys, sizeof (m_Keys)); - std::ofstream fi (ROUTER_INFO); + std::ofstream fi(ROUTER_INFO, std::ios::binary); fi.write ((char *)m_RouterInfo.GetBuffer (), m_RouterInfo.GetBufferLen ()); } } \ No newline at end of file diff --git a/RouterInfo.cpp b/RouterInfo.cpp index d804ecad..a0c40dd7 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -41,7 +41,7 @@ namespace data void RouterInfo::ReadFromFile (const char * filename) { - std::ifstream s(filename); + std::ifstream s(filename, std::ios::binary); if (s.is_open ()) { s.seekg (0,std::ios::end); @@ -95,7 +95,7 @@ namespace data size = be16toh (size); while (r < size) { - char key[50], value[50]; + char key[500], value[500]; r += ReadString (key, s); s.seekg (1, std::ios_base::cur); r++; // = r += ReadString (value, s); @@ -117,7 +117,7 @@ namespace data size = be16toh (size); while (r < size) { - char key[50], value[50]; + char key[500], value[500]; r += ReadString (key, s); s.seekg (1, std::ios_base::cur); r++; // = r += ReadString (value, s); @@ -212,6 +212,16 @@ namespace data { uint8_t len; s.read ((char *)&len, 1); + + //static int count_l = 0; + //count_l++; + //std::cout << count_l << " " << (int)len << std::endl; + //if (len > 40) + //{ + // std::cout << (int)len << std::endl; + //} + + s.read (str, len); str[len] = 0; return len+1; diff --git a/TunnelConfig.h b/TunnelConfig.h index 29fb8575..b6eccda4 100644 --- a/TunnelConfig.h +++ b/TunnelConfig.h @@ -115,8 +115,9 @@ namespace tunnel while (hop) { - delete hop; + auto tmp = hop; hop = hop->next; + delete tmp; } } From a85f95aad3c7c2139280773e510695e5fa2a25a9 Mon Sep 17 00:00:00 2001 From: chertov Date: Wed, 22 Jan 2014 07:27:31 +0400 Subject: [PATCH 05/38] add .gitignor into Win32 --- Win32/.gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Win32/.gitignore diff --git a/Win32/.gitignore b/Win32/.gitignore new file mode 100644 index 00000000..d62f96f6 --- /dev/null +++ b/Win32/.gitignore @@ -0,0 +1,8 @@ +* +!*/ + +!*.sln +!*.vcproj +!*.vcxproj +!*.vcxproj.filters +!.gitignore From 91307d97320c6da63a1a90f85883a5c231896251 Mon Sep 17 00:00:00 2001 From: chertov Date: Wed, 22 Jan 2014 10:46:58 +0400 Subject: [PATCH 06/38] fix endian.h (be64toh) bug --- I2PEndian.cpp | 162 +++++++++++++++++++++++----------------------- I2PEndian.h | 16 +++-- RouterContext.cpp | 6 +- RouterInfo.cpp | 14 +--- portable_endian.h | 115 ++++++++++++++++++++++++++++++++ 5 files changed, 211 insertions(+), 102 deletions(-) create mode 100644 portable_endian.h diff --git a/I2PEndian.cpp b/I2PEndian.cpp index 1fccf47f..fa4e08cb 100644 --- a/I2PEndian.cpp +++ b/I2PEndian.cpp @@ -1,81 +1,81 @@ -#include "I2PEndian.h" - -// http://habrahabr.ru/post/121811/ -// http://codepad.org/2ycmkz2y - -#include "LittleBigEndian.h" - -uint16_t htobe16(uint16_t int16) -{ - BigEndian u16(int16); - return u16.raw_value; -} - -uint32_t htobe32(uint32_t int32) -{ - BigEndian u32(int32); - return u32.raw_value; -} - -uint64_t htobe64(uint64_t int64) -{ - BigEndian u64(int64); - return u64.raw_value; -} - -uint16_t be16toh(uint16_t big16) -{ - LittleEndian u16(big16); - return u16.raw_value; -} - -uint32_t be32toh(uint32_t big32) -{ - LittleEndian u32(big32); - return u32.raw_value; -} - -uint64_t be64toh(uint64_t big64) -{ - LittleEndian u64(big64); - return u64.raw_value; -} - -/* it can be used in Windows 8 -#include - -uint16_t htobe16(uint16_t int16) -{ - return htons(int16); -} - -uint32_t htobe32(uint32_t int32) -{ - return htonl(int32); -} - -uint64_t htobe64(uint64_t int64) -{ - // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx - //return htonll(int64); - return 0; -} - - -uint16_t be16toh(uint16_t big16) -{ - return ntohs(big16); -} - -uint32_t be32toh(uint32_t big32) -{ - return ntohl(big32); -} - -uint64_t be64toh(uint64_t big64) -{ - // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx - //return ntohll(big64); - return 0; -} -*/ \ No newline at end of file +//#include "I2PEndian.h" +// +//// http://habrahabr.ru/post/121811/ +//// http://codepad.org/2ycmkz2y +// +//#include "LittleBigEndian.h" +// +//uint16_t htobe16(uint16_t int16) +//{ +// BigEndian u16(int16); +// return u16.raw_value; +//} +// +//uint32_t htobe32(uint32_t int32) +//{ +// BigEndian u32(int32); +// return u32.raw_value; +//} +// +//uint64_t htobe64(uint64_t int64) +//{ +// BigEndian u64(int64); +// return u64.raw_value; +//} +// +//uint16_t be16toh(uint16_t big16) +//{ +// LittleEndian u16(big16); +// return u16.raw_value; +//} +// +//uint32_t be32toh(uint32_t big32) +//{ +// LittleEndian u32(big32); +// return u32.raw_value; +//} +// +//uint64_t be64toh(uint64_t big64) +//{ +// LittleEndian u64(big64); +// return u64.raw_value; +//} +// +///* it can be used in Windows 8 +//#include +// +//uint16_t htobe16(uint16_t int16) +//{ +// return htons(int16); +//} +// +//uint32_t htobe32(uint32_t int32) +//{ +// return htonl(int32); +//} +// +//uint64_t htobe64(uint64_t int64) +//{ +// // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx +// //return htonll(int64); +// return 0; +//} +// +// +//uint16_t be16toh(uint16_t big16) +//{ +// return ntohs(big16); +//} +// +//uint32_t be32toh(uint32_t big32) +//{ +// return ntohl(big32); +//} +// +//uint64_t be64toh(uint64_t big64) +//{ +// // http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx +// //return ntohll(big64); +// return 0; +//} +//*/ \ No newline at end of file diff --git a/I2PEndian.h b/I2PEndian.h index 01ba73e8..3014f564 100644 --- a/I2PEndian.h +++ b/I2PEndian.h @@ -5,14 +5,16 @@ #include #else #include +// +//uint16_t htobe16(uint16_t int16); +//uint32_t htobe32(uint32_t int32); +//uint64_t htobe64(uint64_t int64); +// +//uint16_t be16toh(uint16_t big16); +//uint32_t be32toh(uint32_t big32); +//uint64_t be64toh(uint64_t big64); -uint16_t htobe16(uint16_t int16); -uint32_t htobe32(uint32_t int32); -uint64_t htobe64(uint64_t int64); - -uint16_t be16toh(uint16_t big16); -uint32_t be32toh(uint32_t big32); -uint64_t be64toh(uint64_t big64); +#include "portable_endian.h" #endif diff --git a/RouterContext.cpp b/RouterContext.cpp index 3274f82d..75a3eb51 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -60,7 +60,7 @@ namespace i2p bool RouterContext::Load () { - std::ifstream fk (ROUTER_KEYS, std::ios::binary); + std::ifstream fk (ROUTER_KEYS, std::ifstream::binary | std::ofstream::in); if (!fk.is_open ()) return false; fk.read ((char *)&m_Keys, sizeof (m_Keys)); @@ -74,10 +74,10 @@ namespace i2p void RouterContext::Save () { - std::ofstream fk (ROUTER_KEYS, std::ios::binary); + std::ofstream fk (ROUTER_KEYS, std::ofstream::binary | std::ofstream::out); fk.write ((char *)&m_Keys, sizeof (m_Keys)); - std::ofstream fi(ROUTER_INFO, std::ios::binary); + std::ofstream fi (ROUTER_INFO, std::ofstream::binary | std::ofstream::out); fi.write ((char *)m_RouterInfo.GetBuffer (), m_RouterInfo.GetBufferLen ()); } } diff --git a/RouterInfo.cpp b/RouterInfo.cpp index c804cadb..41d57117 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -12,6 +12,8 @@ #include "RouterInfo.h" #include "RouterContext.h" + + namespace i2p { namespace data @@ -41,7 +43,7 @@ namespace data void RouterInfo::ReadFromFile (const char * filename) { - std::ifstream s(filename, std::ios::binary); + std::ifstream s(filename, std::ifstream::binary); if (s.is_open ()) { s.seekg (0,std::ios::end); @@ -221,16 +223,6 @@ namespace data { uint8_t len; s.read ((char *)&len, 1); - - //static int count_l = 0; - //count_l++; - //std::cout << count_l << " " << (int)len << std::endl; - //if (len > 40) - //{ - // std::cout << (int)len << std::endl; - //} - - s.read (str, len); str[len] = 0; return len+1; diff --git a/portable_endian.h b/portable_endian.h new file mode 100644 index 00000000..3355d2b9 --- /dev/null +++ b/portable_endian.h @@ -0,0 +1,115 @@ +#ifndef PORTABLE_ENDIAN_H__ +#define PORTABLE_ENDIAN_H__ + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) + +# define __WINDOWS__ + +#endif + +#if defined(__linux__) || defined(__CYGWIN__) + +# include + +#elif defined(__APPLE__) + +# include + +# define htobe16 OSSwapHostToBigInt16 +# define htole16 OSSwapHostToLittleInt16 +# define be16toh OSSwapBigToHostInt16 +# define le16toh OSSwapLittleToHostInt16 + +# define htobe32 OSSwapHostToBigInt32 +# define htole32 OSSwapHostToLittleInt32 +# define be32toh OSSwapBigToHostInt32 +# define le32toh OSSwapLittleToHostInt32 + +# define htobe64 OSSwapHostToBigInt64 +# define htole64 OSSwapHostToLittleInt64 +# define be64toh OSSwapBigToHostInt64 +# define le64toh OSSwapLittleToHostInt64 + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#elif defined(__OpenBSD__) + +# include + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) + +# include + +# define be16toh betoh16 +# define le16toh letoh16 + +# define be32toh betoh32 +# define le32toh letoh32 + +# define be64toh betoh64 +# define le64toh letoh64 + +#elif defined(__WINDOWS__) + +#define INCL_EXTRA_HTON_FUNCTIONS +#define NOMINMAX +# include +#undef NOMINMAX +//# include + +# if BYTE_ORDER == LITTLE_ENDIAN + +# define htobe16 htons +# define htole16(x) (x) +# define be16toh ntohs +# define le16toh(x) (x) + +# define htobe32 htonl +# define htole32(x) (x) +# define be32toh ntohl +# define le32toh(x) (x) + +# define htobe64 htonll +# define htole64(x) (x) +# define be64toh ntohll +# define le64toh(x) (x) + +# elif BYTE_ORDER == BIG_ENDIAN + + /* that would be xbox 360 */ +# define htobe16(x) (x) +# define htole16(x) __builtin_bswap16(x) +# define be16toh(x) (x) +# define le16toh(x) __builtin_bswap16(x) + +# define htobe32(x) (x) +# define htole32(x) __builtin_bswap32(x) +# define be32toh(x) (x) +# define le32toh(x) __builtin_bswap32(x) + +# define htobe64(x) (x) +# define htole64(x) __builtin_bswap64(x) +# define be64toh(x) (x) +# define le64toh(x) __builtin_bswap64(x) + +# else + +# error byte order not supported + +# endif + +# define __BYTE_ORDER BYTE_ORDER +# define __BIG_ENDIAN BIG_ENDIAN +# define __LITTLE_ENDIAN LITTLE_ENDIAN +# define __PDP_ENDIAN PDP_ENDIAN + +#else + +# error platform not supported + +#endif + +#endif \ No newline at end of file From a65400471aeefb356cfdc61bbf0b2b2a0b866653 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2014 07:44:41 -0500 Subject: [PATCH 07/38] use kademlia to pick floodfill for destination --- NetDb.cpp | 43 ++++++++++++++++++++++++++++--------------- NetDb.h | 8 ++++---- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 9b454598..6cf9e251 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -239,16 +239,6 @@ namespace data void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet) { - auto floodfill= GetRandomNTCPRouter (true); - if (floodfill) - RequestDestination (destination, floodfill, isLeaseSet); - else - LogPrint ("No floodfill routers found"); - } - - void NetDb::RequestDestination (const IdentHash& destination, const RouterInfo * floodfill, bool isLeaseSet) - { - if (!floodfill) return; i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); if (outbound) { @@ -256,9 +246,31 @@ namespace data if (inbound) { RequestedDestination * dest = CreateRequestedDestination (destination, isLeaseSet); - dest->SetLastOutboundTunnel (outbound); - auto msg = dest->CreateRequestMessage (floodfill, inbound); - outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg); + 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) + }); + + outbound->SendTunnelDataMsg (msgs); + } + else + LogPrint ("No more floodfills found"); } else LogPrint ("No inbound tunnels found"); @@ -487,7 +499,8 @@ namespace data if (msg) m_Queue.Put (msg); } - const RouterInfo * NetDb::GetClosestFloodfill (const IdentHash& destination) const + const RouterInfo * NetDb::GetClosestFloodfill (const IdentHash& destination, + const std::set& excluded) const { RouterInfo * r = nullptr; XORMetric minMetric; @@ -495,7 +508,7 @@ namespace data minMetric.SetMax (); for (auto it: m_RouterInfos) { - if (it.second->IsFloodfill () &&! it.second->IsUnreachable ()) + if (it.second->IsFloodfill () &&! it.second->IsUnreachable () && !excluded.count (it.first)) { XORMetric m = destKey ^ it.second->GetRoutingKey (); if (m < minMetric) diff --git a/NetDb.h b/NetDb.h index 02a585ef..75c2c81b 100644 --- a/NetDb.h +++ b/NetDb.h @@ -26,7 +26,8 @@ namespace data const IdentHash& GetDestination () const { return m_Destination; }; int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); }; - const RouterInfo * GetLastRouter () const { return m_LastRouter; }; + const std::set& GetExcludedPeers () { return m_ExcludedPeers; }; + const RouterInfo * GetLastRouter () const { return m_LastRouter; }; const i2p::tunnel::InboundTunnel * GetLastReplyTunnel () const { return m_LastReplyTunnel; }; bool IsExploratory () const { return m_IsExploratory; }; bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); }; @@ -62,8 +63,7 @@ namespace data void RequestDestination (const char * b32); // in base32 void RequestDestination (const IdentHash& destination, bool isLeaseSet = false); - void RequestDestination (const IdentHash& destination, const RouterInfo * floodfill, bool isLeaseSet = false); - + void HandleDatabaseStoreMsg (uint8_t * buf, size_t len); void HandleDatabaseSearchReplyMsg (I2NPMessage * msg); @@ -78,7 +78,7 @@ namespace data void SaveUpdated (const char * directory); void Run (); // exploratory thread void Explore (); - const RouterInfo * GetClosestFloodfill (const IdentHash& destination) const; + const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set& excluded) const; RequestedDestination * CreateRequestedDestination (const IdentHash& dest, bool isLeaseSet, bool isExploratory = false); From 1afc493e90467947383ceffffacd4e3951eb9a68 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2014 07:51:55 -0500 Subject: [PATCH 08/38] bigger buffer size temporary for win32 --- RouterInfo.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 41d57117..ee9a60c2 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -128,7 +128,13 @@ namespace data size = be16toh (size); while (r < size) { +#ifdef _WIN32 char key[500], value[500]; + // TODO: investigate why properties get read as one long string under Windows + // length should not be more than 44 +#else + char key[50], value[50]; +#endif r += ReadString (key, s); s.seekg (1, std::ios_base::cur); r++; // = r += ReadString (value, s); From dc8dac51f7a878c926bac44edba3b1c84cf43132 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2014 15:32:50 -0500 Subject: [PATCH 09/38] download RouterInfo through HTTP --- NetDb.cpp | 38 ++++++++++++++++++++++++++++++++++++++ NetDb.h | 1 + 2 files changed, 39 insertions(+) diff --git a/NetDb.cpp b/NetDb.cpp index 6cf9e251..a39d7ee1 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -1,6 +1,7 @@ #include "I2PEndian.h" #include #include +#include #include #include #include "base64.h" @@ -520,5 +521,42 @@ namespace data } return r; } + + 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 75c2c81b..03be5ed6 100644 --- a/NetDb.h +++ b/NetDb.h @@ -76,6 +76,7 @@ namespace data void Load (const char * directory); void SaveUpdated (const char * directory); + void DownloadRouterInfo (const std::string& address, const std::string& filename); // for reseed void Run (); // exploratory thread void Explore (); const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set& excluded) const; From 2b87a58685da4ecf0725a1ce60dc6568d6e0f720 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2014 17:19:54 -0500 Subject: [PATCH 10/38] fixed build with boost 1.46 --- NetDb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NetDb.cpp b/NetDb.cpp index a39d7ee1..17b6f9b8 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -529,7 +529,7 @@ namespace data boost::asio::ip::tcp::iostream site(address, "http"); if (!site) { - site.expires_from_now (boost::posix_time::seconds (10)); // wait for 10 seconds + //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; From 6c6d013a7642a8e7b8c64ea8611386a2cf1faca0 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2014 20:19:39 -0500 Subject: [PATCH 11/38] clean-up from obsolete RouterInfos --- NetDb.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 17b6f9b8..084b10ab 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -207,6 +207,8 @@ namespace data }; int count = 0, deletedCount = 0; + auto total = m_RouterInfos.size (); + uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); for (auto it: m_RouterInfos) { if (it.second->IsUpdated ()) @@ -216,13 +218,20 @@ namespace data it.second->SetUpdated (false); count++; } - else if (it.second->IsUnreachable ()) + else { - if (boost::filesystem::exists (GetFilePath (directory, it.second))) - { - boost::filesystem::remove (GetFilePath (directory, it.second)); - deletedCount++; - } + // RouterInfo expires in 72 hours if more than 300 + if (total > 300 && ts > it.second->GetTimestamp () + 3*24*3600*1000LL) // 3 days + it.second->SetUnreachable (true); + + if (it.second->IsUnreachable ()) + { + if (boost::filesystem::exists (GetFilePath (directory, it.second))) + { + boost::filesystem::remove (GetFilePath (directory, it.second)); + deletedCount++; + } + } } } if (count > 0) From 6385f4554e5b49edba4d01ae0aebd392f40a9867 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2014 20:48:08 -0500 Subject: [PATCH 12/38] make sure not all routers get deleted after long break --- NetDb.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NetDb.cpp b/NetDb.cpp index 084b10ab..a00e900d 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -222,7 +222,10 @@ namespace data { // RouterInfo expires in 72 hours if more than 300 if (total > 300 && ts > it.second->GetTimestamp () + 3*24*3600*1000LL) // 3 days + { + total--; it.second->SetUnreachable (true); + } if (it.second->IsUnreachable ()) { From d7d3fcef94cec4ae05f1c5e03780ffb8647a2f7e Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 23 Jan 2014 13:03:37 -0500 Subject: [PATCH 13/38] implementation of HMAC-MD5-128 --- hmac.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 hmac.h diff --git a/hmac.h b/hmac.h new file mode 100644 index 00000000..7b77af28 --- /dev/null +++ b/hmac.h @@ -0,0 +1,60 @@ +#ifndef HMAC_H__ +#define HMAC_H__ + +#include +#include +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 +#include + +namespace i2p +{ +namespace crypto +{ + const uint64_t IPAD = 0x3636363636363636; + const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C; + + inline void HMACMD5Digest (uint8_t * msg, size_t len, uint8_t * key, uint8_t * digest) + // key is 32 bytes + // digest is 16 bytes + // block size is 64 bytes + { + size_t totalLen = len + 64 + 32; + uint8_t * buf = new uint8_t[totalLen]; // TODO: reuse buffers + // ikeypad + ((uint64_t *)buf)[0] = ((uint64_t *)key)[0] ^ IPAD; + ((uint64_t *)buf)[1] = ((uint64_t *)key)[1] ^ IPAD; + ((uint64_t *)buf)[2] = ((uint64_t *)key)[2] ^ IPAD; + ((uint64_t *)buf)[3] = ((uint64_t *)key)[3] ^ IPAD; + ((uint64_t *)buf)[4] = IPAD; + ((uint64_t *)buf)[5] = IPAD; + ((uint64_t *)buf)[6] = IPAD; + ((uint64_t *)buf)[7] = IPAD; + // concatenate with msg + memcpy (buf + 64, msg, len); + // calculate first hash + uint8_t hash[16]; // MD5 + CryptoPP::Weak1::MD5().CalculateDigest (hash, buf, len + 64); + + // okeypad + ((uint64_t *)buf)[0] = ((uint64_t *)key)[0] ^ OPAD; + ((uint64_t *)buf)[1] = ((uint64_t *)key)[1] ^ OPAD; + ((uint64_t *)buf)[2] = ((uint64_t *)key)[2] ^ OPAD; + ((uint64_t *)buf)[3] = ((uint64_t *)key)[3] ^ OPAD; + ((uint64_t *)buf)[4] = OPAD; + ((uint64_t *)buf)[5] = OPAD; + ((uint64_t *)buf)[6] = OPAD; + ((uint64_t *)buf)[7] = OPAD; + // copy first hash after okeypad + memcpy (buf + 64, hash, 16); + // fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P) + memset (buf + 72, 0, 16); + + // calculate digest + CryptoPP::Weak1::MD5().CalculateDigest (digest, buf, totalLen); + delete[] buf; + } +} +} + +#endif + From 3cf3e69aef309bb1096d1f16655a747a661622c0 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 23 Jan 2014 16:10:33 -0500 Subject: [PATCH 14/38] SSU added --- Makefile | 2 +- SSU.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ SSU.h | 36 ++++++++++++++++++++++++++++++++++++ Transports.cpp | 21 +++++++++++++++++++-- Transports.h | 2 ++ 5 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 SSU.cpp create mode 100644 SSU.h diff --git a/Makefile b/Makefile index 1fec1950..84c7a32f 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 + 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 LIBS = diff --git a/SSU.cpp b/SSU.cpp new file mode 100644 index 00000000..45788ed4 --- /dev/null +++ b/SSU.cpp @@ -0,0 +1,44 @@ +#include +#include "Log.h" +#include "hmac.h" +#include "SSU.h" + +namespace i2p +{ +namespace ssu +{ + SSUServer::SSUServer (boost::asio::io_service& service, int port): + m_Socket (service, boost::asio::ip::udp::v4 (), port) + { + } + + void SSUServer::Start () + { + Receive (); + } + + void SSUServer::Stop () + { + m_Socket.close (); + } + + void SSUServer::Receive () + { + m_Socket.async_receive_from (boost::asio::buffer (m_ReceiveBuffer, SSU_MTU), m_SenderEndpoint, + boost::bind (&SSUServer::HandleReceivedFrom, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + + void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (!ecode) + { + LogPrint ("SSU received ", bytes_transferred, " bytes"); + // Handle + Receive (); + } + else + LogPrint ("SSU receive error: ", ecode.message ()); + } +} +} + diff --git a/SSU.h b/SSU.h new file mode 100644 index 00000000..0cbc31f1 --- /dev/null +++ b/SSU.h @@ -0,0 +1,36 @@ +#ifndef SSU_H__ +#define SSU_H__ + +#include +#include + +namespace i2p +{ +namespace ssu +{ + const int SSU_MTU = 1484; + + class SSUServer + { + public: + + SSUServer (boost::asio::io_service& service, int port); + void Start (); + void Stop (); + + private: + + void Receive (); + void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred); + + private: + + boost::asio::ip::udp::socket m_Socket; + boost::asio::ip::udp::endpoint m_SenderEndpoint; + uint8_t m_ReceiveBuffer[SSU_MTU]; + }; +} +} + +#endif + diff --git a/Transports.cpp b/Transports.cpp index 31d0325f..c3b96d78 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -12,7 +12,7 @@ namespace i2p Transports transports; Transports::Transports (): - m_Thread (0), m_Work (m_Service),m_NTCPAcceptor (0) + m_Thread (nullptr), m_Work (m_Service),m_NTCPAcceptor (nullptr), m_SSUServer (nullptr) { } @@ -34,11 +34,22 @@ namespace i2p m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port)); - LogPrint ("Start listening port ", address.port); + LogPrint ("Start listening TCP port ", address.port); auto conn = new i2p::ntcp::NTCPServerConnection (m_Service); m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this, conn, boost::asio::placeholders::error)); } + else if (address.transportStyle == RouterInfo::eTransportSSU) + { + if (!m_SSUServer) + { + m_SSUServer = new i2p::ssu::SSUServer (m_Service, address.port); + LogPrint ("Start listening UDP port ", address.port); + m_SSUServer->Start (); + } + else + LogPrint ("SSU server already exists"); + } } } @@ -49,6 +60,12 @@ namespace i2p m_NTCPSessions.clear (); delete m_NTCPAcceptor; + if (m_SSUServer) + { + m_SSUServer->Stop (); + delete m_SSUServer; + } + m_IsRunning = false; m_Service.stop (); if (m_Thread) diff --git a/Transports.h b/Transports.h index d6b08227..03f6cf35 100644 --- a/Transports.h +++ b/Transports.h @@ -7,6 +7,7 @@ #include #include #include "NTCPSession.h" +#include "SSU.h" #include "RouterInfo.h" #include "I2NPProtocol.h" @@ -47,6 +48,7 @@ namespace i2p boost::asio::ip::tcp::acceptor * m_NTCPAcceptor; std::map m_NTCPSessions; + i2p::ssu::SSUServer * m_SSUServer; public: From 9e91be671dd10d5a3677e7cd169e98e975fc0116 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 24 Jan 2014 16:30:07 -0500 Subject: [PATCH 15/38] SSU payload types --- SSU.cpp | 27 ++++++++++++++++++++++++++- SSU.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/SSU.cpp b/SSU.cpp index 45788ed4..aebab995 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -7,11 +7,26 @@ namespace i2p { namespace ssu { + + SSUSession::SSUSession (): m_State (eSessionStateUnknown) + { + } + + void SSUSession::ProcessNextMessage (uint8_t * buf, std::size_t len) + { + } + SSUServer::SSUServer (boost::asio::io_service& service, int port): m_Socket (service, boost::asio::ip::udp::v4 (), port) { } + SSUServer::~SSUServer () + { + for (auto it: m_Sessions) + delete it.second; + } + void SSUServer::Start () { Receive (); @@ -33,7 +48,17 @@ namespace ssu if (!ecode) { LogPrint ("SSU received ", bytes_transferred, " bytes"); - // Handle + SSUSession * session = nullptr; + auto it = m_Sessions.find (m_SenderEndpoint); + if (it != m_Sessions.end ()) + session = it->second; + if (session) + { + session = new SSUSession (); + 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); Receive (); } else diff --git a/SSU.h b/SSU.h index 0cbc31f1..8bb2c6fa 100644 --- a/SSU.h +++ b/SSU.h @@ -2,6 +2,7 @@ #define SSU_H__ #include +#include #include namespace i2p @@ -10,11 +11,46 @@ namespace ssu { const int SSU_MTU = 1484; + // 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_RELAY_REQUEST = 3; + const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4; + const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5; + const uint8_t PAYLOAD_TYPE_DATA = 6; + const uint8_t PAYLOAD_TYPE_TEST = 7; + + enum SessionState + { + eSessionStateUnknown, + eSessionStateRequestSent, + eSessionStateRequestReceived, + eSessionStateCreatedSent, + eSessionStateCreatedReceived, + eSessionStateConfirmedSent, + eSessionStateConfirmedReceived, + eSessionStateEstablised + }; + + class SSUSession + { + public: + + SSUSession (); + void ProcessNextMessage (uint8_t * buf, std::size_t len); + + private: + + SessionState m_State; + }; + class SSUServer { public: SSUServer (boost::asio::io_service& service, int port); + ~SSUServer (); void Start (); void Stop (); @@ -28,6 +64,7 @@ namespace ssu boost::asio::ip::udp::socket m_Socket; boost::asio::ip::udp::endpoint m_SenderEndpoint; uint8_t m_ReceiveBuffer[SSU_MTU]; + std::map m_Sessions; }; } } From bd8ea0bac03ac5e55b077c7a6ce4dcc1f2ea3311 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 24 Jan 2014 20:53:15 -0500 Subject: [PATCH 16/38] use any router for second hop of tunnel --- NetDb.cpp | 7 +++++-- Tunnel.cpp | 9 ++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index a00e900d..05d9d9fa 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -499,12 +499,15 @@ namespace data { 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) { - if (i >= ind) return it.second; + if (!it.second->IsUnreachable ()) + last = it.second; + if (i >= ind) break; else i++; } - return nullptr; + return last; } void NetDb::PostI2NPMsg (I2NPMessage * msg) diff --git a/Tunnel.cpp b/Tunnel.cpp index f92337f7..fe904369 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -395,16 +395,15 @@ namespace tunnel } else { - //OutboundTunnel * outboundTunnel = GetNextOutboundTunnel (); + LogPrint ("Creating two hops outbound tunnel..."); CreateTunnel ( new TunnelConfig (std::vector { - i2p::data::netdb.GetRandomNTCPRouter (), - i2p::data::netdb.GetRandomNTCPRouter () + i2p::data::netdb.GetRandomNTCPRouter (), // first hop must be NTCP + i2p::data::netdb.GetRandomRouter () }, - inboundTunnel->GetTunnelConfig ())/*, - outboundTunnel*/); + inboundTunnel->GetTunnelConfig ())); } } } From ef7e81baae746d3ac887f948d5df79649b11d38a Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 24 Jan 2014 21:14:14 -0500 Subject: [PATCH 17/38] fixed crash --- Garlic.cpp | 2 +- NetDb.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Garlic.cpp b/Garlic.cpp index ad824fd7..cdb8860e 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -236,8 +236,8 @@ namespace garlic auto it = m_Sessions.find (destination->GetIdentHash ()); if (it != m_Sessions.end ()) { - m_Sessions.erase (it); delete it->second; + m_Sessions.erase (it); } GarlicRoutingSession * session = new GarlicRoutingSession (destination, 0); // not follow-on messages expected m_Sessions[destination->GetIdentHash ()] = session; diff --git a/NetDb.cpp b/NetDb.cpp index 05d9d9fa..3e6b83fa 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -412,8 +412,8 @@ namespace data else { // no more requests for detination possible. delete it - m_RequestedDestinations.erase (it); delete it->second; + m_RequestedDestinations.erase (it); } } else @@ -474,8 +474,8 @@ namespace data auto it = m_RequestedDestinations.find (dest); if (it != m_RequestedDestinations.end ()) { - m_RequestedDestinations.erase (it); delete it->second; + m_RequestedDestinations.erase (it); } } From bc3bf838d95e502c5281e28e3a85204be6605cfc Mon Sep 17 00:00:00 2001 From: chertov Date: Sat, 25 Jan 2014 10:58:11 +0400 Subject: [PATCH 18/38] fix NetDb save bug, console cyrillic symbols, add files to project --- NetDb.cpp | 2 +- Win32/i2pd.vcxproj | 2 ++ Win32/i2pd.vcxproj.filters | 6 ++++++ i2p.cpp | 8 ++++++++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/NetDb.cpp b/NetDb.cpp index 3e6b83fa..75669260 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -213,7 +213,7 @@ namespace data { if (it.second->IsUpdated ()) { - std::ofstream r (GetFilePath(directory, it.second)); + std::ofstream r (GetFilePath(directory, it.second), std::ofstream::binary); r.write ((char *)it.second->GetBuffer (), it.second->GetBufferLen ()); it.second->SetUpdated (false); count++; diff --git a/Win32/i2pd.vcxproj b/Win32/i2pd.vcxproj index a98c7449..353e8afa 100644 --- a/Win32/i2pd.vcxproj +++ b/Win32/i2pd.vcxproj @@ -24,6 +24,7 @@ + @@ -48,6 +49,7 @@ + diff --git a/Win32/i2pd.vcxproj.filters b/Win32/i2pd.vcxproj.filters index 39abceab..152edb53 100644 --- a/Win32/i2pd.vcxproj.filters +++ b/Win32/i2pd.vcxproj.filters @@ -72,6 +72,9 @@ Source Files + + Source Files + @@ -149,5 +152,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/i2p.cpp b/i2p.cpp index e2b44dfe..51c6d1eb 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -13,6 +13,14 @@ int main( int, char** ) { + +#ifdef _WIN32 + setlocale(LC_CTYPE, ""); + SetConsoleCP(1251); + SetConsoleOutputCP(1251); + setlocale(LC_ALL, "Russian"); +#endif + i2p::util::HTTPServer httpServer (7070); httpServer.Start (); From a4c25e773cfa9afcde1f2c0700f330c94d8cdedf Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 25 Jan 2014 21:47:01 -0500 Subject: [PATCH 19/38] 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 20/38] 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 21/38] 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 22/38] 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 23/38] 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 24/38] 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 25/38] 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 26/38] 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 27/38] 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 28/38] 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 29/38] 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 30/38] 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 31/38] 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 32/38] 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 33/38] 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 34/38] 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 35/38] 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 36/38] 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 37/38] 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 38/38] 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 (); }; };