diff --git a/AddressBook.cpp b/AddressBook.cpp index 22008294..f972d48f 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -330,8 +330,7 @@ namespace client LoadHostsFromStream (f); m_IsLoaded = true; } - // load local - m_Storage->LoadLocal (m_Addresses); + LoadLocal (); } void AddressBook::LoadHostsFromStream (std::istream& f) @@ -395,6 +394,40 @@ namespace client LogPrint (eLogError, "Addressbook: subscriptions already loaded"); } + void AddressBook::LoadLocal () + { + std::map localAddresses; + m_Storage->LoadLocal (localAddresses); + for (auto it: localAddresses) + { + auto dot = it.first.find ('.'); + if (dot != std::string::npos) + { + auto domain = it.first.substr (dot + 1); + auto it1 = m_Addresses.find (domain); // find domain in our addressbook + if (it1 != m_Addresses.end ()) + { + auto dest = context.FindLocalDestination (it1->second); + if (dest) + { + // address is ours + std::shared_ptr resolver; + auto it2 = m_Resolvers.find (it1->second); + if (it2 != m_Resolvers.end ()) + resolver = it2->second; // resolver exists + else + { + // create new resolver + resolver = std::make_shared(dest); + m_Resolvers.insert (std::make_pair(it1->second, resolver)); + } + resolver->AddAddress (it.first, it.second); + } + } + } + } + } + bool AddressBook::GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified) { if (m_Storage) @@ -653,6 +686,50 @@ namespace client m_Book.LoadHostsFromStream (s); return true; } + + AddressResolver::AddressResolver (std::shared_ptr destination): + m_LocalDestination (destination) + { + if (m_LocalDestination) + { + auto datagram = m_LocalDestination->GetDatagramDestination (); + if (!datagram) + datagram = m_LocalDestination->CreateDatagramDestination (); + datagram->SetReceiver (std::bind (&AddressResolver::HandleRequest, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5), + ADDRESS_RESOLVER_DATAGRAM_PORT); + } + } + + void AddressResolver::HandleRequest (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + { + if (len < 9 || len < buf[8] + 9U) + { + LogPrint (eLogError, "Address request is too short ", len); + return; + } + // read requested address + uint8_t l = buf[8]; + char address[255]; + memcpy (address, buf + 9, l); + address[l] = 0; + // send response + uint8_t response[40]; + memset (response, 0, 4); // reserved + memcpy (response + 4, buf + 4, 4); // nonce + auto it = m_LocalAddresses.find (address); // address lookup + if (it != m_LocalAddresses.end ()) + memcpy (response + 8, it->second, 32); // ident + else + memset (response + 8, 0, 32); // not found + m_LocalDestination->GetDatagramDestination ()->SendDatagramTo (response, 40, from.GetIdentHash (), toPort, fromPort); + } + + void AddressResolver::AddAddress (const std::string& name, const i2p::data::IdentHash& ident) + { + m_LocalAddresses[name] = ident; + } + } } diff --git a/AddressBook.h b/AddressBook.h index 98422fe1..436e7c8b 100644 --- a/AddressBook.h +++ b/AddressBook.h @@ -12,6 +12,7 @@ #include "Base.h" #include "Identity.h" #include "Log.h" +#include "Destination.h" namespace i2p { @@ -23,7 +24,7 @@ namespace client const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours) const int CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT = 5; // in minutes const int SUBSCRIPTION_REQUEST_TIMEOUT = 60; //in second - + inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); } class AddressBookStorage // interface for storage @@ -45,6 +46,7 @@ namespace client }; class AddressBookSubscription; + class AddressResolver; class AddressBook { public: @@ -74,13 +76,15 @@ namespace client void LoadHosts (); void LoadSubscriptions (); + void LoadLocal (); void HandleSubscriptionsUpdateTimer (const boost::system::error_code& ecode); private: std::mutex m_AddressBookMutex; - std::map m_Addresses, m_LocalAddresses; + std::map m_Addresses; + std::map > m_Resolvers; // local destination->resolver AddressBookStorage * m_Storage; volatile bool m_IsLoaded, m_IsDownloading; std::vector m_Subscriptions; @@ -106,6 +110,24 @@ namespace client std::string m_Link, m_Etag, m_LastModified; // m_Etag must be surrounded by "" }; + + const uint16_t ADDRESS_RESOLVER_DATAGRAM_PORT = 53; + class AddressResolver + { + public: + + AddressResolver (std::shared_ptr destination); + void AddAddress (const std::string& name, const i2p::data::IdentHash& ident); + + private: + + void HandleRequest (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + + private: + + std::shared_ptr m_LocalDestination; + std::map m_LocalAddresses; + }; } } diff --git a/Config.cpp b/Config.cpp index caec7e20..5e775e74 100644 --- a/Config.cpp +++ b/Config.cpp @@ -117,6 +117,7 @@ namespace config { ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") + ("ipv4", value()->zero_tokens()->default_value(true), "Enable communication through ipv4") ("ipv6", value()->zero_tokens()->default_value(false), "Enable communication through ipv6") ("daemon", value()->zero_tokens()->default_value(false), "Router will go to background after start") ("service", value()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") diff --git a/Daemon.cpp b/Daemon.cpp index f301ee3a..bd89250e 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -72,7 +72,7 @@ namespace i2p if (config == "") { config = i2p::fs::DataDirPath("i2p.conf"); - // use i2p.cong only if exists + // use i2p.conf only if exists if (!i2p::fs::Exists (config)) config = ""; /* reset */ } @@ -104,9 +104,11 @@ namespace i2p i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host)); } - bool ipv6; i2p::config::GetOption("ipv6", ipv6); + bool ipv6; i2p::config::GetOption("ipv6", ipv6); + bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool transit; i2p::config::GetOption("notransit", transit); - i2p::context.SetSupportsV6 (ipv6); + i2p::context.SetSupportsV6 (ipv6); + i2p::context.SetSupportsV4 (ipv4); i2p::context.SetAcceptsTunnels (!transit); bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill); diff --git a/HTTPServer.cpp b/HTTPServer.cpp index ddfa6478..67ddf362 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -427,18 +427,18 @@ namespace util s << " (" << i2p::transport::transports.GetOutBandwidth () <<" Bps)
\r\n"; s << "Data path: " << i2p::fs::GetDataDir() << "
\r\n
\r\n"; s << "Our external address:" << "
\r\n" ; - for (auto& address : i2p::context.GetRouterInfo().GetAddresses()) + for (auto address : i2p::context.GetRouterInfo().GetAddresses()) { - switch (address.transportStyle) + switch (address->transportStyle) { case i2p::data::RouterInfo::eTransportNTCP: - if (address.host.is_v6 ()) + if (address->host.is_v6 ()) s << "NTCP6  "; else s << "NTCP  "; break; case i2p::data::RouterInfo::eTransportSSU: - if (address.host.is_v6 ()) + if (address->host.is_v6 ()) s << "SSU6     "; else s << "SSU     "; @@ -446,7 +446,7 @@ namespace util default: s << "Unknown  "; } - s << address.host.to_string() << ":" << address.port << "
\r\n"; + s << address->host.to_string() << ":" << address->port << "
\r\n"; } s << "
\r\nRouters: " << i2p::data::netdb.GetNumRouters () << " "; s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " "; @@ -534,7 +534,7 @@ namespace util auto dest = i2p::client::context.FindLocalDestination (ident); if (dest) { - s << "Base64:
\r\n
\r\n
\r\n"; s << "LeaseSets: " << dest->GetNumRemoteLeaseSets () << "
\r\n"; auto pool = dest->GetTunnelPool (); diff --git a/NTCPSession.cpp b/NTCPSession.cpp index b0ea2e74..a7832335 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -759,15 +759,15 @@ namespace transport m_IsRunning = true; m_Thread = new std::thread (std::bind (&NTCPServer::Run, this)); // create acceptors - auto addresses = context.GetRouterInfo ().GetAddresses (); - for (auto& address : addresses) + auto& addresses = context.GetRouterInfo ().GetAddresses (); + for (auto address: addresses) { - if (address.transportStyle == i2p::data::RouterInfo::eTransportNTCP && address.host.is_v4 ()) + if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP && address->host.is_v4 ()) { m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, - boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port)); + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port)); - LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address.port); + LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address->port); auto conn = std::make_shared(*this); m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this, conn, std::placeholders::_1)); @@ -777,10 +777,10 @@ namespace transport m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service); m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6()); m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true)); - m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address.port)); + m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port)); m_NTCPV6Acceptor->listen (); - LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address.port); + LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address->port); auto conn = std::make_shared (*this); m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, this, conn, std::placeholders::_1)); diff --git a/NetDb.cpp b/NetDb.cpp index eb1380de..857381d8 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -118,6 +118,7 @@ namespace data { SaveUpdated (); ManageLeaseSets (); + ManageLookupResponses (); } lastSave = ts; } @@ -671,13 +672,31 @@ namespace data if (!replyMsg) { LogPrint (eLogWarning, "NetDb: Requested ", key, " not found. ", numExcluded, " excluded"); - std::set excludedRouters; - for (int i = 0; i < numExcluded; i++) - { - excludedRouters.insert (excluded); - excluded += 32; + // find or cleate response + std::vector closestFloodfills; + bool found = false; + if (!numExcluded) + { + auto it = m_LookupResponses.find (ident); + if (it != m_LookupResponses.end ()) + { + closestFloodfills = it->second.first; + found = true; + } + } + if (!found) + { + std::set excludedRouters; + for (int i = 0; i < numExcluded; i++) + { + excludedRouters.insert (excluded); + excluded += 32; + } + closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true); + if (!numExcluded) // save if no excluded + m_LookupResponses[ident] = std::make_pair(closestFloodfills, i2p::util::GetSecondsSinceEpoch ()); } - replyMsg = CreateDatabaseSearchReply (ident, GetClosestFloodfills (ident, 3, excludedRouters, true)); + replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills); } } @@ -972,5 +991,17 @@ namespace data it++; } } + + void NetDb::ManageLookupResponses () + { + auto ts = i2p::util::GetSecondsSinceEpoch (); + for (auto it = m_LookupResponses.begin (); it != m_LookupResponses.end ();) + { + if (ts > it->second.second + 180) // 3 minutes + it = m_LookupResponses.erase (it); + else + it++; + } + } } } diff --git a/NetDb.h b/NetDb.h index 536ff644..1c062358 100644 --- a/NetDb.h +++ b/NetDb.h @@ -84,6 +84,7 @@ namespace data void Publish (); void ManageLeaseSets (); void ManageRequests (); + void ManageLookupResponses (); template std::shared_ptr GetRandomRouter (Filter filter) const; @@ -108,6 +109,8 @@ namespace data friend class NetDbRequests; NetDbRequests m_Requests; + + std::map, uint64_t> > m_LookupResponses; // ident->(closest FFs, timestamp) }; extern NetDb netdb; diff --git a/RouterContext.cpp b/RouterContext.cpp index b3774d89..2157a81e 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -92,11 +92,11 @@ namespace i2p void RouterContext::UpdatePort (int port) { bool updated = false; - for (auto& address : m_RouterInfo.GetAddresses ()) + for (auto address : m_RouterInfo.GetAddresses ()) { - if (address.port != port) + if (address->port != port) { - address.port = port; + address->port = port; updated = true; } } @@ -107,11 +107,11 @@ namespace i2p void RouterContext::UpdateAddress (const boost::asio::ip::address& host) { bool updated = false; - for (auto& address : m_RouterInfo.GetAddresses ()) + for (auto address : m_RouterInfo.GetAddresses ()) { - if (address.host != host && address.IsCompatible (host)) + if (address->host != host && address->IsCompatible (host)) { - address.host = host; + address->host = host; updated = true; } } @@ -206,15 +206,15 @@ namespace i2p auto& addresses = m_RouterInfo.GetAddresses (); for (size_t i = 0; i < addresses.size (); i++) { - if (addresses[i].transportStyle == i2p::data::RouterInfo::eTransportNTCP) + if (addresses[i]->transportStyle == i2p::data::RouterInfo::eTransportNTCP) { addresses.erase (addresses.begin () + i); break; } } // delete previous introducers - for (auto& addr : addresses) - addr.introducers.clear (); + for (auto addr : addresses) + addr->introducers.clear (); // update UpdateRouterInfo (); @@ -235,16 +235,16 @@ namespace i2p auto& addresses = m_RouterInfo.GetAddresses (); for (size_t i = 0; i < addresses.size (); i++) { - if (addresses[i].transportStyle == i2p::data::RouterInfo::eTransportSSU) + if (addresses[i]->transportStyle == i2p::data::RouterInfo::eTransportSSU) { // insert NTCP address with host/port from SSU - m_RouterInfo.AddNTCPAddress (addresses[i].host.to_string ().c_str (), addresses[i].port); + m_RouterInfo.AddNTCPAddress (addresses[i]->host.to_string ().c_str (), addresses[i]->port); break; } } // delete previous introducers - for (auto& addr : addresses) - addr.introducers.clear (); + for (auto addr : addresses) + addr->introducers.clear (); // update UpdateRouterInfo (); @@ -257,26 +257,36 @@ namespace i2p else m_RouterInfo.DisableV6 (); UpdateRouterInfo (); - } + } + + void RouterContext::SetSupportsV4 (bool supportsV4) + { + if (supportsV4) + m_RouterInfo.EnableV4 (); + else + m_RouterInfo.DisableV4 (); + UpdateRouterInfo (); + } + void RouterContext::UpdateNTCPV6Address (const boost::asio::ip::address& host) { bool updated = false, found = false; int port = 0; auto& addresses = m_RouterInfo.GetAddresses (); - for (auto& addr : addresses) + for (auto addr: addresses) { - if (addr.host.is_v6 () && addr.transportStyle == i2p::data::RouterInfo::eTransportNTCP) + if (addr->host.is_v6 () && addr->transportStyle == i2p::data::RouterInfo::eTransportNTCP) { - if (addr.host != host) + if (addr->host != host) { - addr.host = host; + addr->host = host; updated = true; } found = true; } else - port = addr.port; + port = addr->port; } if (!found) { diff --git a/RouterContext.h b/RouterContext.h index bc1ee836..0679a038 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -64,7 +64,10 @@ namespace i2p bool AcceptsTunnels () const { return m_AcceptsTunnels; }; void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; }; bool SupportsV6 () const { return m_RouterInfo.IsV6 (); }; + bool SupportsV4 () const { return m_RouterInfo.IsV4 (); }; void SetSupportsV6 (bool supportsV6); + void SetSupportsV4 (bool supportsV4); + void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session void UpdateStats (); diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 84768201..22c5f2f8 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -232,7 +232,7 @@ namespace data } if (isValidAddress) { - m_Addresses.push_back(address); + m_Addresses.push_back(std::make_shared
(address)); m_SupportedTransports |= supportedTransports; } } @@ -359,8 +359,9 @@ namespace data // addresses uint8_t numAddresses = m_Addresses.size (); s.write ((char *)&numAddresses, sizeof (numAddresses)); - for (auto& address : m_Addresses) + for (auto addr : m_Addresses) { + Address& address = *addr; s.write ((char *)&address.cost, sizeof (address.cost)); s.write ((char *)&address.date, sizeof (address.date)); std::stringstream properties; @@ -543,46 +544,46 @@ namespace data void RouterInfo::AddNTCPAddress (const char * host, int port) { - Address addr; - addr.host = boost::asio::ip::address::from_string (host); - addr.port = port; - addr.transportStyle = eTransportNTCP; - addr.cost = 2; - addr.date = 0; - addr.mtu = 0; + auto addr = std::make_shared
(); + addr->host = boost::asio::ip::address::from_string (host); + addr->port = port; + addr->transportStyle = eTransportNTCP; + addr->cost = 2; + addr->date = 0; + addr->mtu = 0; for (auto it: m_Addresses) // don't insert same address twice - if (it == addr) return; + if (*it == *addr) return; m_Addresses.push_back(addr); - m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eNTCPV4; + m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4; } void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu) { - Address addr; - addr.host = boost::asio::ip::address::from_string (host); - addr.port = port; - addr.transportStyle = eTransportSSU; - addr.cost = 10; // NTCP should have priority over SSU - addr.date = 0; - addr.mtu = mtu; - memcpy (addr.key, key, 32); + auto addr = std::make_shared
(); + addr->host = boost::asio::ip::address::from_string (host); + addr->port = port; + addr->transportStyle = eTransportSSU; + addr->cost = 10; // NTCP should have priority over SSU + addr->date = 0; + addr->mtu = mtu; + memcpy (addr->key, key, 32); for (auto it: m_Addresses) // don't insert same address twice - if (it == addr) return; + if (*it == *addr) return; m_Addresses.push_back(addr); - m_SupportedTransports |= addr.host.is_v6 () ? eSSUV6 : eSSUV4; + m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4; m_Caps |= eSSUTesting; m_Caps |= eSSUIntroducer; } bool RouterInfo::AddIntroducer (const Introducer& introducer) { - for (auto& addr : m_Addresses) + for (auto addr : m_Addresses) { - if (addr.transportStyle == eTransportSSU && addr.host.is_v4 ()) + if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) { - for (auto intro: addr.introducers) + for (auto intro: addr->introducers) if (intro.iTag == introducer.iTag) return false; // already presented - addr.introducers.push_back (introducer); + addr->introducers.push_back (introducer); return true; } } @@ -591,14 +592,14 @@ namespace data bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e) { - for (auto& addr : m_Addresses) + for (auto addr: m_Addresses) { - if (addr.transportStyle == eTransportSSU && addr.host.is_v4 ()) + if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) { - for (std::vector::iterator it = addr.introducers.begin (); it != addr.introducers.end (); it++) + for (std::vector::iterator it = addr->introducers.begin (); it != addr->introducers.end (); it++) if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e) { - addr.introducers.erase (it); + addr->introducers.erase (it); return true; } } @@ -650,12 +651,24 @@ namespace data return m_SupportedTransports & (eNTCPV6 | eSSUV6); } + bool RouterInfo::IsV4 () const + { + return m_SupportedTransports & (eNTCPV4 | eSSUV4); + } + void RouterInfo::EnableV6 () { if (!IsV6 ()) m_SupportedTransports |= eNTCPV6 | eSSUV6; } - + + void RouterInfo::EnableV4 () + { + if (!IsV4 ()) + m_SupportedTransports |= eNTCPV4 | eSSUV4; + } + + void RouterInfo::DisableV6 () { if (IsV6 ()) @@ -664,8 +677,8 @@ namespace data m_SupportedTransports &= ~eNTCPV6; for (size_t i = 0; i < m_Addresses.size (); i++) { - if (m_Addresses[i].transportStyle == i2p::data::RouterInfo::eTransportNTCP && - m_Addresses[i].host.is_v6 ()) + if (m_Addresses[i]->transportStyle == i2p::data::RouterInfo::eTransportNTCP && + m_Addresses[i]->host.is_v6 ()) { m_Addresses.erase (m_Addresses.begin () + i); break; @@ -676,8 +689,8 @@ namespace data m_SupportedTransports &= ~eSSUV6; for (size_t i = 0; i < m_Addresses.size (); i++) { - if (m_Addresses[i].transportStyle == i2p::data::RouterInfo::eTransportSSU && - m_Addresses[i].host.is_v6 ()) + if (m_Addresses[i]->transportStyle == i2p::data::RouterInfo::eTransportSSU && + m_Addresses[i]->host.is_v6 ()) { m_Addresses.erase (m_Addresses.begin () + i); break; @@ -685,35 +698,66 @@ namespace data } } } - + + void RouterInfo::DisableV4 () + { + if (IsV4 ()) + { + // NTCP + m_SupportedTransports &= ~eNTCPV4; + for (size_t i = 0; i < m_Addresses.size (); i++) + { + if (m_Addresses[i]->transportStyle == i2p::data::RouterInfo::eTransportNTCP && + m_Addresses[i]->host.is_v4 ()) + { + m_Addresses.erase (m_Addresses.begin () + i); + break; + } + } + + // SSU + m_SupportedTransports &= ~eSSUV4; + for (size_t i = 0; i < m_Addresses.size (); i++) + { + if (m_Addresses[i]->transportStyle == i2p::data::RouterInfo::eTransportSSU && + m_Addresses[i]->host.is_v4 ()) + { + m_Addresses.erase (m_Addresses.begin () + i); + break; + } + } + } + } + + bool RouterInfo::UsesIntroducer () const { return m_Caps & Caps::eUnreachable; // non-reachable } - const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const + std::shared_ptr RouterInfo::GetNTCPAddress (bool v4only) const { return GetAddress (eTransportNTCP, v4only); } - const RouterInfo::Address * RouterInfo::GetSSUAddress (bool v4only) const + std::shared_ptr RouterInfo::GetSSUAddress (bool v4only) const { return GetAddress (eTransportSSU, v4only); } - const RouterInfo::Address * RouterInfo::GetSSUV6Address () const + std::shared_ptr RouterInfo::GetSSUV6Address () const { return GetAddress (eTransportSSU, false, true); } - const RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const + std::shared_ptr RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const { - for (auto& address : m_Addresses) + for (auto address : m_Addresses) { - if (address.transportStyle == s) + if (address->transportStyle == s) { - if ((!v4only || address.host.is_v4 ()) && (!v6only || address.host.is_v6 ())) - return &address; + if ((!v4only || address->host.is_v4 ()) && (!v6only || address->host.is_v6 ())) + return address; } } return nullptr; diff --git a/RouterInfo.h b/RouterInfo.h index c0ef2131..5fa865b0 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -116,10 +116,10 @@ namespace data void SetRouterIdentity (std::shared_ptr identity); std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); }; uint64_t GetTimestamp () const { return m_Timestamp; }; - std::vector
& GetAddresses () { return m_Addresses; }; - const Address * GetNTCPAddress (bool v4only = true) const; - const Address * GetSSUAddress (bool v4only = true) const; - const Address * GetSSUV6Address () const; + std::vector >& GetAddresses () { return m_Addresses; }; + std::shared_ptr GetNTCPAddress (bool v4only = true) const; + std::shared_ptr GetSSUAddress (bool v4only = true) const; + std::shared_ptr GetSSUV6Address () const; void AddNTCPAddress (const char * host, int port); void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0); @@ -133,8 +133,11 @@ namespace data bool IsNTCP (bool v4only = true) const; bool IsSSU (bool v4only = true) const; bool IsV6 () const; + bool IsV4 () const; void EnableV6 (); void DisableV6 (); + void EnableV4 (); + void DisableV4 (); bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; bool UsesIntroducer () const; bool IsIntroducer () const { return m_Caps & eSSUIntroducer; }; @@ -182,7 +185,7 @@ namespace data size_t ReadString (char * str, std::istream& s); void WriteString (const std::string& str, std::ostream& s); void ExtractCaps (const char * value); - const Address * GetAddress (TransportStyle s, bool v4only, bool v6only = false) const; + std::shared_ptr GetAddress (TransportStyle s, bool v4only, bool v6only = false) const; void UpdateCapsProperty (); private: @@ -192,7 +195,7 @@ namespace data uint8_t * m_Buffer; size_t m_BufferLen; uint64_t m_Timestamp; - std::vector
m_Addresses; + std::vector > m_Addresses; std::map m_Properties; bool m_IsUpdated, m_IsUnreachable; uint8_t m_SupportedTransports, m_Caps; diff --git a/Transports.cpp b/Transports.cpp index 9b327133..275c6f90 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -112,8 +112,8 @@ namespace transport m_IsRunning = true; m_Thread = new std::thread (std::bind (&Transports::Run, this)); // create acceptors - auto addresses = context.GetRouterInfo ().GetAddresses (); - for (auto& address : addresses) + auto& addresses = context.GetRouterInfo ().GetAddresses (); + for (auto address : addresses) { if (!m_NTCPServer) { @@ -121,12 +121,12 @@ namespace transport m_NTCPServer->Start (); } - if (address.transportStyle == RouterInfo::eTransportSSU && address.host.is_v4 ()) + if (address->transportStyle == RouterInfo::eTransportSSU && address->host.is_v4 ()) { if (!m_SSUServer) { - m_SSUServer = new SSUServer (address.port); - LogPrint (eLogInfo, "Transports: Start listening UDP port ", address.port); + m_SSUServer = new SSUServer (address->port); + LogPrint (eLogInfo, "Transports: Start listening UDP port ", address->port); m_SSUServer->Start (); DetectExternalIP (); } @@ -376,14 +376,24 @@ namespace transport auto& peer = it1->second; if (!ecode && peer.router) { - auto address = (*it).endpoint ().address (); - LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address); - auto addr = peer.router->GetNTCPAddress (); - if (addr) - { - auto s = std::make_shared (*m_NTCPServer, peer.router); - m_NTCPServer->Connect (address, addr->port, s); - return; + while (it != boost::asio::ip::tcp::resolver::iterator()) + { + auto address = (*it).endpoint ().address (); + LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address); + if (address.is_v4 () || context.SupportsV6 ()) + { + auto addr = peer.router->GetNTCPAddress (); // TODO: take one we requested + if (addr) + { + auto s = std::make_shared (*m_NTCPServer, peer.router); + m_NTCPServer->Connect (address, addr->port, s); + return; + } + break; + } + else + LogPrint (eLogInfo, "Transports: NTCP ", address, " is not supported"); + it++; } } LogPrint (eLogError, "Transports: Unable to resolve NTCP address: ", ecode.message ()); @@ -409,13 +419,23 @@ namespace transport auto& peer = it1->second; if (!ecode && peer.router) { - auto address = (*it).endpoint ().address (); - LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address); - auto addr = peer.router->GetSSUAddress (!context.SupportsV6 ());; - if (addr) - { - m_SSUServer->CreateSession (peer.router, address, addr->port); - return; + while (it != boost::asio::ip::tcp::resolver::iterator()) + { + auto address = (*it).endpoint ().address (); + LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address); + if (address.is_v4 () || context.SupportsV6 ()) + { + auto addr = peer.router->GetSSUAddress (); // TODO: take one we requested + if (addr) + { + m_SSUServer->CreateSession (peer.router, address, addr->port); + return; + } + break; + } + else + LogPrint (eLogInfo, "Transports: SSU ", address, " is not supported"); + it++; } } LogPrint (eLogError, "Transports: Unable to resolve SSU address: ", ecode.message ()); diff --git a/UPnP.cpp b/UPnP.cpp index c4e5e04c..fea2ff9e 100644 --- a/UPnP.cpp +++ b/UPnP.cpp @@ -101,19 +101,19 @@ namespace transport void UPnP::Run () { - std::vector a = context.GetRouterInfo().GetAddresses(); - for (auto& address : a) + const std::vector > a = context.GetRouterInfo().GetAddresses(); + for (auto address : a) { - if (!address.host.is_v6 ()) + if (!address->host.is_v6 ()) { Discover (); - if (address.transportStyle == data::RouterInfo::eTransportSSU ) + if (address->transportStyle == data::RouterInfo::eTransportSSU ) { - TryPortMapping (I2P_UPNP_UDP, address.port); + TryPortMapping (I2P_UPNP_UDP, address->port); } - else if (address.transportStyle == data::RouterInfo::eTransportNTCP ) + else if (address->transportStyle == data::RouterInfo::eTransportNTCP ) { - TryPortMapping (I2P_UPNP_TCP, address.port); + TryPortMapping (I2P_UPNP_TCP, address->port); } } } diff --git a/UPnP.h b/UPnP.h index 1a7b55c5..32c42118 100644 --- a/UPnP.h +++ b/UPnP.h @@ -58,6 +58,5 @@ namespace transport } } -#endif - -#endif +#endif // USE_UPNP +#endif // __UPNP_H__ diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index f2915498..81a3ba48 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -2,6 +2,7 @@ #include #include #include "../Config.h" +#include "../version.h" #include "resource.h" #include "Win32App.h" #include @@ -90,7 +91,9 @@ namespace win32 { case ID_ABOUT: { - MessageBox( hWnd, TEXT("i2pd"), TEXT("About"), MB_ICONINFORMATION | MB_OK ); + std::stringstream text; + text << "Version: " << I2PD_VERSION << " " << CODENAME; + MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK ); return 0; } case ID_EXIT: @@ -171,12 +174,12 @@ namespace win32 auto mascot = LoadBitmap (GetModuleHandle(NULL), MAKEINTRESOURCE (MASCOT)); auto mascotDC = CreateCompatibleDC (hDC); SelectObject (mascotDC, mascot); - BitBlt (hDC, 0,0, 533, 700, mascotDC, 0, 0, SRCCOPY); + BitBlt (hDC, 0,0, 533, 700, mascotDC, 0, 0, SRCCOPY); DeleteDC (mascotDC); DeleteObject (mascot); EndPaint (hWnd, &ps); break; - } + } } return DefWindowProc( hWnd, uMsg, wParam, lParam); } @@ -205,7 +208,7 @@ namespace win32 wclx.lpszClassName = I2PD_WIN32_CLASSNAME; RegisterClassEx (&wclx); // create new window - if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPEDWINDOW, 100, 100, 533, 700, NULL, NULL, hInst, NULL)) + if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPEDWINDOW, 100, 100, 549, 738, NULL, NULL, hInst, NULL)) { MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST); return false; diff --git a/docs/build_requirements.md b/docs/build_requirements.md index 3f523a80..ec4aa180 100644 --- a/docs/build_requirements.md +++ b/docs/build_requirements.md @@ -4,7 +4,7 @@ Build requirements Linux/FreeBSD/OSX ----------------- -GCC 4.6 or newer, Boost 1.46 or newer, openssl, zlib. Clang can be used instead of GCC. +GCC 4.8 or newer, Boost 1.49 or newer, openssl, zlib. Clang can be used instead of GCC. Windows ------- diff --git a/docs/family.md b/docs/family.md index 0f307143..8ef76b7a 100644 --- a/docs/family.md +++ b/docs/family.md @@ -8,11 +8,11 @@ New family ----------- You must create family self-signed certificate and key. The only key type supposted is prime256v1. -Use the following list of commands: -openssl ecparam -name prime256v1 -genkey -out .key -openssl req -new -key .key -out .csr -touch v3.ext -openssl x509 -req -days 3650 -in .csr -signkey .key -out .crt -extfile v3.ext +Use the following list of commands: +openssl ecparam -name prime256v1 -genkey -out .key +openssl req -new -key .key -out .csr +touch v3.ext +openssl x509 -req -days 3650 -in .csr -signkey .key -out .crt -extfile v3.ext specify .family.i2p.net for CN. diff --git a/util.cpp b/util.cpp index bd77e682..5230f55f 100644 --- a/util.cpp +++ b/util.cpp @@ -106,11 +106,15 @@ namespace http while (!response.eof ()) { std::string hexLen; - int len; + size_t len; std::getline (response, hexLen); std::istringstream iss (hexLen); iss >> std::hex >> len; - if (!len) break; + if (!len || len > 10000000L) // 10M + { + LogPrint (eLogError, "Unexpected chunk length ", len); + break; + } char * buf = new char[len]; response.read (buf, len); merged.write (buf, len); diff --git a/version.h b/version.h index 244096b7..e7414de3 100644 --- a/version.h +++ b/version.h @@ -16,7 +16,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 24 +#define I2P_VERSION_MICRO 25 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)