diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 9fd0aae4..5e4eb4a4 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -270,6 +270,12 @@ namespace config { ("ntcp2.proxy", value()->default_value(""), "Proxy URL for NTCP2 transport") ; + options_description ssu2("SSU2 Options"); + ntcp2.add_options() + ("ssu2.enabled", value()->default_value(false), "Enable SSU2 (default: disabled)") + ("ssu2.port", value()->default_value(0), "Port to listen for incoming SSU2 packets (default: auto)") + ; + options_description nettime("Time sync options"); nettime.add_options() ("nettime.enabled", value()->default_value(false), "Disable time sync (default: disabled)") @@ -320,6 +326,7 @@ namespace config { .add(websocket) // deprecated .add(exploratory) .add(ntcp2) + .add(ssu2) .add(nettime) .add(persist) .add(cpuext) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 533d718c..ec8d9fea 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -69,11 +69,14 @@ namespace i2p bool ipv6; i2p::config::GetOption("ipv6", ipv6); bool ssu; i2p::config::GetOption("ssu", ssu); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); + bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); bool nat; i2p::config::GetOption("nat", nat); if ((ntcp2 || ygg) && !m_NTCP2Keys) NewNTCP2Keys (); + if (ssu2 && !m_SSU2Keys) + NewSSU2Keys (); bool ntcp2Published = false; if (ntcp2) { @@ -112,6 +115,11 @@ namespace i2p routerInfo.AddSSUAddress (host.c_str(), port, nullptr); caps |= i2p::data::RouterInfo::eReachable; // R } + if (ssu2) + { + addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4; + routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey); + } } if (ipv6) { @@ -147,6 +155,12 @@ namespace i2p routerInfo.AddSSUAddress (host.c_str(), port, nullptr); caps |= i2p::data::RouterInfo::eReachable; // R } + if (ssu2) + { + if (!ipv4) // no other ssu2 addresses yet + routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey); + addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6; + } } if (ygg) { @@ -313,6 +327,32 @@ namespace i2p UpdateRouterInfo (); } + void RouterContext::UpdateSSU2Address (bool enable) + { + auto& addresses = m_RouterInfo.GetAddresses (); + bool found = false, updated = false; + for (auto it = addresses.begin (); it != addresses.end (); ++it) + { + if ((*it)->IsSSU2 ()) + { + found = true; + if (!enable) + { + addresses.erase (it); + updated= true; + } + break; + } + } + if (enable && !found) + { + m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey); + updated = true; + } + if (updated) + UpdateRouterInfo (); + } + void RouterContext::UpdateAddress (const boost::asio::ip::address& host) { bool updated = false; @@ -807,6 +847,30 @@ namespace i2p else UpdateNTCP2Address (false); // disable NTCP2 + // read SSU2 + bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); + if (ssu2) + { + // read SSU2 keys if available + std::ifstream s2k (i2p::fs::DataDirPath (SSU2_KEYS), std::ifstream::in | std::ifstream::binary); + if (s2k) + { + s2k.seekg (0, std::ios::end); + size_t len = s2k.tellg(); + s2k.seekg (0, std::ios::beg); + if (len == sizeof (SSU2PrivateKeys)) + { + m_SSU2Keys.reset (new SSU2PrivateKeys ()); + s2k.read ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys)); + } + s2k.close (); + } + if (!m_SSU2Keys) NewSSU2Keys (); + UpdateSSU2Address (false); // enable SSU2 + } + else + UpdateSSU2Address (false); // disable SSU2 + return true; } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 714b3623..93a72211 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -116,6 +116,7 @@ namespace garlic void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg); void UpdateNTCP2Address (bool enable); + void UpdateSSU2Address (bool enable); void RemoveNTCPAddress (bool v4only = true); // delete NTCP address for older routers. TODO: remove later bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 27def6eb..c3afbf9a 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -631,6 +631,16 @@ namespace data m_Addresses->push_back(std::move(addr)); } + void RouterInfo::AddSSU2Address (const uint8_t * staticKey) + { + auto addr = std::make_shared
(); + addr->transportStyle = eTransportSSU2; + addr->caps = 0; + addr->date = 0; + memcpy (addr->s, staticKey, 32); + m_Addresses->push_back(std::move(addr)); + } + bool RouterInfo::AddIntroducer (const Introducer& introducer) { for (auto& addr : *m_Addresses) @@ -925,7 +935,7 @@ namespace data for (auto& addr: *m_Addresses) { // TODO: implement SSU - if (addr->transportStyle == eTransportNTCP && !addr->IsPublishedNTCP2 ()) + if (!addr->published && (addr->transportStyle == eTransportNTCP || addr->transportStyle == eTransportSSU2)) { addr->caps &= ~(eV4 | eV6); addr->caps |= transports; @@ -1050,6 +1060,8 @@ namespace data cost = address.published ? COST_NTCP2_PUBLISHED : COST_NTCP2_NON_PUBLISHED; else if (address.transportStyle == eTransportSSU) cost = address.published ? COST_SSU_DIRECT : COST_SSU_THROUGH_INTRODUCERS; + else if (address.transportStyle == eTransportSSU2) + cost = COST_SSU2_NON_PUBLISHED; // TODO s.write ((const char *)&cost, sizeof (cost)); s.write ((const char *)&address.date, sizeof (address.date)); std::stringstream properties; diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 4a6d29a5..511098bc 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -53,7 +53,8 @@ namespace data const uint8_t COST_NTCP2_NON_PUBLISHED = 14; const uint8_t COST_SSU_DIRECT = 9; const uint8_t COST_SSU_THROUGH_INTRODUCERS = 11; - + const uint8_t COST_SSU2_NON_PUBLISHED = 15; + const size_t MAX_RI_BUFFER_SIZE = 2048; // if RouterInfo exceeds 2048 we consider it as malformed, might be changed later class RouterInfo: public RoutingDestination { @@ -189,6 +190,7 @@ namespace data void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0); void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv, const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0); + void AddSSU2Address (const uint8_t * staticKey); // non published bool AddIntroducer (const Introducer& introducer); bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps