From b1fcd4d27bebd1bc5b5aee15778900a1764911a4 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 17 Feb 2021 14:26:48 -0500 Subject: [PATCH 01/26] show actual IP addresses for proxy connections --- daemon/HTTPServer.cpp | 8 +++--- libi2pd/NTCP2.cpp | 56 +++++++++++++++++++++++++----------------- libi2pd/NTCP2.h | 22 ++++++----------- libi2pd/Transports.cpp | 17 +++---------- 4 files changed, 49 insertions(+), 54 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index aba30fd7..0847f85d 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -706,23 +706,23 @@ namespace http { std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0; for (const auto& it: sessions ) { - if (it.second && it.second->IsEstablished () && !it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) + if (it.second && it.second->IsEstablished () && !it.second->GetRemoteEndpoint ().address ().is_v6 ()) { tmp_s << "
\r\n"; if (it.second->IsOutgoing ()) tmp_s << " ⇒ "; tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " - << it.second->GetSocket ().remote_endpoint().address ().to_string (); + << it.second->GetRemoteEndpoint ().address ().to_string (); if (!it.second->IsOutgoing ()) tmp_s << " ⇒ "; tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; tmp_s << "
\r\n" << std::endl; cnt++; } - if (it.second && it.second->IsEstablished () && it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) + if (it.second && it.second->IsEstablished () && it.second->GetRemoteEndpoint ().address ().is_v6 ()) { tmp_s6 << "
\r\n"; if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " - << "[" << it.second->GetSocket ().remote_endpoint().address ().to_string () << "]"; + << "[" << it.second->GetRemoteEndpoint ().address ().to_string () << "]"; if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; tmp_s6 << "
\r\n" << std::endl; diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index dc485d5b..dd777794 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -339,6 +339,7 @@ namespace transport { memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); + m_RemoteEndpoint = boost::asio::ip::tcp::endpoint (addr->host, addr->port); } else LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); @@ -1274,10 +1275,15 @@ namespace transport return nullptr; } - void NTCP2Server::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn) + void NTCP2Server::Connect(std::shared_ptr conn) { - LogPrint (eLogDebug, "NTCP2: Connecting to ", address ,":", port); - GetService ().post([this, address, port, conn]() + if (!conn || conn->GetRemoteEndpoint ().address ().is_unspecified ()) + { + LogPrint (eLogError, "NTCP2: Can't connect to unspecified address"); + return; + } + LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint ()); + GetService ().post([this, conn]() { if (this->AddNTCP2Session (conn)) { @@ -1295,7 +1301,7 @@ namespace transport conn->Terminate (); } }); - conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer)); + conn->GetSocket ().async_connect (conn->GetRemoteEndpoint (), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer)); } else conn->Terminate (); @@ -1312,7 +1318,7 @@ namespace transport } else { - LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetSocket ().remote_endpoint ()); + LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint ()); conn->ClientLogin (); } } @@ -1328,6 +1334,7 @@ namespace transport LogPrint (eLogDebug, "NTCP2: Connected from ", ep); if (conn) { + conn->SetRemoteEndpoint (ep); conn->ServerLogin (); m_PendingIncomingSessions.push_back (conn); conn = nullptr; @@ -1361,6 +1368,7 @@ namespace transport LogPrint (eLogDebug, "NTCP2: Connected from ", ep); if (conn) { + conn->SetRemoteEndpoint (ep); conn->ServerLogin (); m_PendingIncomingSessions.push_back (conn); } @@ -1415,13 +1423,13 @@ namespace transport } } - void NTCP2Server::ConnectWithProxy (const std::string& host, uint16_t port, RemoteAddressType addrtype, std::shared_ptr conn) + void NTCP2Server::ConnectWithProxy (std::shared_ptr conn) { if(!m_ProxyEndpoint) return; - GetService().post([this, host, port, addrtype, conn]() { + GetService().post([this, conn]() + { if (this->AddNTCP2Session (conn)) { - auto timer = std::make_shared(GetService()); auto timeout = NTCP2_CONNECT_TIMEOUT * 5; conn->SetTerminationTimeout(timeout * 2); @@ -1435,7 +1443,7 @@ namespace transport conn->Terminate (); } }); - conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer, host, port, addrtype)); + conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer)); } }); } @@ -1447,7 +1455,7 @@ namespace transport m_ProxyPort = port; } - void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) + void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer) { if (ecode) { @@ -1473,7 +1481,7 @@ namespace transport }); auto readbuff = std::make_shared >(2); boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 2), - [this, readbuff, timer, conn, host, port, addrtype](const boost::system::error_code & ec, std::size_t transferred) + [this, readbuff, timer, conn](const boost::system::error_code & ec, std::size_t transferred) { if(ec) { @@ -1486,7 +1494,7 @@ namespace transport { if((*readbuff)[1] == 0x00) { - AfterSocksHandshake(conn, timer, host, port, addrtype); + AfterSocksHandshake(conn, timer); return; } else if ((*readbuff)[1] == 0xff) @@ -1506,13 +1514,14 @@ namespace transport } case eHTTPProxy: { + auto& ep = conn->GetRemoteEndpoint (); i2p::http::HTTPReq req; req.method = "CONNECT"; req.version ="HTTP/1.1"; - if(addrtype == eIP6Address) - req.uri = "[" + host + "]:" + std::to_string(port); + if(ep.address ().is_v6 ()) + req.uri = "[" + ep.address ().to_string() + "]:" + std::to_string(ep.port ()); else - req.uri = host + ":" + std::to_string(port); + req.uri = ep.address ().to_string() + ":" + std::to_string(ep.port ()); boost::asio::streambuf writebuff; std::ostream out(&writebuff); @@ -1566,7 +1575,7 @@ namespace transport } } - void NTCP2Server::AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) + void NTCP2Server::AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer) { // build request size_t sz = 6; // header + port @@ -1576,27 +1585,28 @@ namespace transport (*buff)[1] = 0x01; (*buff)[2] = 0x00; - if(addrtype == eIP4Address) + auto& ep = conn->GetRemoteEndpoint (); + if(ep.address ().is_v4 ()) { (*buff)[3] = 0x01; - auto addrbytes = boost::asio::ip::address::from_string(host).to_v4().to_bytes(); + auto addrbytes = ep.address ().to_v4().to_bytes(); sz += 4; memcpy(buff->data () + 4, addrbytes.data(), 4); } - else if (addrtype == eIP6Address) + else if (ep.address ().is_v6 ()) { (*buff)[3] = 0x04; - auto addrbytes = boost::asio::ip::address::from_string(host).to_v6().to_bytes(); + auto addrbytes = ep.address ().to_v6().to_bytes(); sz += 16; memcpy(buff->data () + 4, addrbytes.data(), 16); } - else if (addrtype == eHostname) + else { // We mustn't really fall here because all connections are made to IP addresses - LogPrint(eLogError, "NTCP2: Tried to connect to domain name via socks proxy"); + LogPrint(eLogError, "NTCP2: Tried to connect to unexpected address via proxy"); return; } - htobe16buf(buff->data () + sz - 2, port); + htobe16buf(buff->data () + sz - 2, ep.port ()); boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff->data (), sz), boost::asio::transfer_all(), [buff](const boost::system::error_code & ec, std::size_t written) { diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index a7708872..c3909225 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -134,6 +134,8 @@ namespace transport void Close () { m_Socket.close (); }; // for accept boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; + const boost::asio::ip::tcp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; + void SetRemoteEndpoint (const boost::asio::ip::tcp::endpoint& ep) { m_RemoteEndpoint = ep; }; bool IsEstablished () const { return m_IsEstablished; }; bool IsTerminated () const { return m_IsTerminated; }; @@ -189,6 +191,7 @@ namespace transport NTCP2Server& m_Server; boost::asio::ip::tcp::socket m_Socket; + boost::asio::ip::tcp::endpoint m_RemoteEndpoint; bool m_IsEstablished, m_IsTerminated; std::unique_ptr m_Establisher; @@ -221,13 +224,6 @@ namespace transport { public: - enum RemoteAddressType - { - eIP4Address, - eIP6Address, - eHostname - }; - enum ProxyType { eNoProxy, @@ -246,11 +242,8 @@ namespace transport void RemoveNTCP2Session (std::shared_ptr session); std::shared_ptr FindNTCP2Session (const i2p::data::IdentHash& ident); - void ConnectWithProxy (const std::string& addr, uint16_t port, RemoteAddressType addrtype, std::shared_ptr conn); - void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn); - - void AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype); - + void ConnectWithProxy (std::shared_ptr conn); + void Connect(std::shared_ptr conn); bool UsingProxy() const { return m_ProxyType != eNoProxy; }; void UseProxy(ProxyType proxy, const std::string & address, uint16_t port); @@ -261,8 +254,9 @@ namespace transport void HandleAcceptV6 (std::shared_ptr conn, const boost::system::error_code& error); void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer); - void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType adddrtype); - + void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer); + void AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer); + // timer void ScheduleTermination (); void HandleTerminationTimer (const boost::system::error_code& ecode); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 2eadda85..6bed627f 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -418,19 +418,10 @@ namespace transport if (address) { auto s = std::make_shared (*m_NTCP2Server, peer.router, address); - - if(m_NTCP2Server->UsingProxy()) - { - NTCP2Server::RemoteAddressType remote = NTCP2Server::eIP4Address; - std::string addr = address->host.to_string(); - - if(address->host.is_v6()) - remote = NTCP2Server::eIP6Address; - - m_NTCP2Server->ConnectWithProxy(addr, address->port, remote, s); - } + if( m_NTCP2Server->UsingProxy()) + m_NTCP2Server->ConnectWithProxy(s); else - m_NTCP2Server->Connect (address->host, address->port, s); + m_NTCP2Server->Connect (s); return true; } } @@ -480,7 +471,7 @@ namespace transport if (address) { auto s = std::make_shared (*m_NTCP2Server, peer.router, address); - m_NTCP2Server->Connect (address->host, address->port, s); + m_NTCP2Server->Connect (s); return true; } } From 1ca0354cf2153c3cd43c97171ce933bbd2e4582c Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 17 Feb 2021 18:46:41 -0500 Subject: [PATCH 02/26] find NTCP2 address by static key. Don't make router unreachable if can't connect by NTCP2 --- libi2pd/NTCP2.cpp | 24 ++++++++---------------- libi2pd/RouterInfo.cpp | 7 ++++--- libi2pd/RouterInfo.h | 2 +- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index dd777794..61e766ea 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -333,8 +333,6 @@ namespace transport if (in_RemoteRouter) // Alice { m_Establisher->m_RemoteIdentHash = GetRemoteIdentity ()->GetIdentHash (); - if (!addr) - addr = in_RemoteRouter->GetNTCP2Address (true); // we need a published address if (addr) { memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); @@ -342,7 +340,7 @@ namespace transport m_RemoteEndpoint = boost::asio::ip::tcp::endpoint (addr->host, addr->port); } else - LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); + LogPrint (eLogWarning, "NTCP2: Missing NTCP2 address"); } m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL + rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD; @@ -658,19 +656,13 @@ namespace transport SendTerminationAndTerminate (eNTCP2Message3Error); return; } - auto addr = ri.GetNTCP2Address (false); // any NTCP2 address + auto addr = ri.GetNTCP2AddressWithStaticKey (m_Establisher->m_RemoteStaticKey); if (!addr) { - LogPrint (eLogError, "NTCP2: No NTCP2 address found in SessionConfirmed"); + LogPrint (eLogError, "NTCP2: No NTCP2 address wth static key found in SessionConfirmed"); Terminate (); return; } - if (memcmp (addr->ntcp2->staticKey, m_Establisher->m_RemoteStaticKey, 32)) - { - LogPrint (eLogError, "NTCP2: Static key mismatch in SessionConfirmed"); - SendTerminationAndTerminate (eNTCP2IncorrectSParameter); - return; - } i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, buf.data () + 3, size)); // TODO: should insert ri and not parse it twice // TODO: process options @@ -1296,8 +1288,6 @@ namespace transport if (ecode != boost::asio::error::operation_aborted) { LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds"); - if (conn->GetRemoteIdentity ()) - i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); conn->Terminate (); } }); @@ -1426,6 +1416,11 @@ namespace transport void NTCP2Server::ConnectWithProxy (std::shared_ptr conn) { if(!m_ProxyEndpoint) return; + if (!conn || conn->GetRemoteEndpoint ().address ().is_unspecified ()) + { + LogPrint (eLogError, "NTCP2: Can't connect to unspecified address"); + return; + } GetService().post([this, conn]() { if (this->AddNTCP2Session (conn)) @@ -1439,7 +1434,6 @@ namespace transport if (ecode != boost::asio::error::operation_aborted) { LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds"); - i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); conn->Terminate (); } }); @@ -1633,8 +1627,6 @@ namespace transport return; } } - if(!e) - i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); timer->cancel(); conn->Terminate(); }); diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 8da49fc6..424f23c5 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -962,12 +962,13 @@ namespace data return nullptr; } - std::shared_ptr RouterInfo::GetNTCP2Address (bool publishedOnly) const + std::shared_ptr RouterInfo::GetNTCP2AddressWithStaticKey (const uint8_t * key) const { + if (!key) return nullptr; return GetAddress ( - [publishedOnly](std::shared_ptr address)->bool + [key](std::shared_ptr address)->bool { - return address->IsNTCP2 () && (!publishedOnly || address->IsPublishedNTCP2 ()); + return address->IsNTCP2 () && !memcmp (address->ntcp2->staticKey, key, 32); }); } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 45670ee5..c712545e 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -150,7 +150,7 @@ namespace data uint64_t GetTimestamp () const { return m_Timestamp; }; int GetVersion () const { return m_Version; }; Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr - std::shared_ptr GetNTCP2Address (bool publishedOnly) const; + std::shared_ptr GetNTCP2AddressWithStaticKey (const uint8_t * key) const; std::shared_ptr GetPublishedNTCP2V4Address () const; std::shared_ptr GetPublishedNTCP2V6Address () const; std::shared_ptr GetSSUAddress (bool v4only = true) const; From d65bc068dee388356a4d6e00b72aafe200e51c4b Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 17 Feb 2021 21:12:17 -0500 Subject: [PATCH 03/26] create ipv4 and ipv6 NTCP2 addresses separately --- libi2pd/RouterContext.cpp | 71 +++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 6183f2be..1cfc71db 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -77,6 +77,12 @@ namespace i2p std::string ifname; i2p::config::GetOption("ifname", ifname); std::string ifname4; i2p::config::GetOption("ifname4", ifname4); std::string ifname6; i2p::config::GetOption("ifname6", ifname6); + + if ((ntcp2 || ygg) && !m_NTCP2Keys) + NewNTCP2Keys (); + bool ntcp2Published = false; + if (ntcp2) + i2p::config::GetOption("ntcp2.published", ntcp2Published); uint8_t caps = 0; if (ipv4) { @@ -86,10 +92,16 @@ namespace i2p else if (!nat && !ifname.empty()) /* bind to interface, we have no NAT so set external address too */ host = i2p::util::net::GetInterfaceAddress(ifname, false).to_string(); // v4 - if(ifname4.size()) host = i2p::util::net::GetInterfaceAddress(ifname4, false).to_string(); + if (ntcp2) + { + if (ntcp2Published) + m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v4::from_string (host), port); + else // add non-published NTCP2 address + routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + } if (ssu) { routerInfo.AddSSUAddress (host.c_str(), port, nullptr); @@ -103,16 +115,35 @@ namespace i2p i2p::config::GetOption("host", host); else if (!ifname.empty()) host = i2p::util::net::GetInterfaceAddress(ifname, true).to_string(); // v6 - if(ifname6.size()) host = i2p::util::net::GetInterfaceAddress(ifname6, true).to_string(); - + + if (ntcp2) + { + if (ntcp2Published) + { + std::string ntcp2Host; + if (!i2p::config::IsDefault ("ntcp2.addressv6")) + i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host); + else + ntcp2Host = host; + routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v6::from_string (ntcp2Host), port); + } + else if (!ipv4) // no other ntcp2 addresses yet + routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + } if (ssu) { routerInfo.AddSSUAddress (host.c_str(), port, nullptr); caps |= i2p::data::RouterInfo::eReachable; // R } } + if (ygg) + { + auto yggaddr = i2p::util::net::GetYggdrasilAddress (); + if (!yggaddr.is_unspecified ()) + routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, yggaddr, port); + } routerInfo.SetCaps (caps); // caps + L routerInfo.SetProperty ("netId", std::to_string (m_NetID)); @@ -120,40 +151,6 @@ namespace i2p routerInfo.CreateBuffer (m_Keys); m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); - - if (ntcp2) // we don't store iv in the address if non published so we must update it from keys - { - if (!m_NTCP2Keys) NewNTCP2Keys (); - bool published; i2p::config::GetOption("ntcp2.published", published); - if (ipv4 || !published) UpdateNTCP2Address (true); // create not published NTCP2 address - if (published) - { - if (ipv4) - PublishNTCP2Address (port, true); - if (ipv6) - { - // add NTCP2 ipv6 address - std::string host = "::1"; - if (!i2p::config::IsDefault ("ntcp2.addressv6")) - i2p::config::GetOption ("ntcp2.addressv6", host); - m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v6::from_string (host), port); - } - } - // enable added NTCP2 addresses - if (ipv4) m_RouterInfo.EnableV4 (); - if (ipv6) m_RouterInfo.EnableV6 (); - } - if (ygg) - { - auto yggaddr = i2p::util::net::GetYggdrasilAddress (); - if (!yggaddr.is_unspecified ()) - { - if (!m_NTCP2Keys) NewNTCP2Keys (); - m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, yggaddr, port); - m_RouterInfo.EnableMesh (); - UpdateRouterInfo (); - } - } } void RouterContext::UpdateRouterInfo () From 94659ba890cdaa48dd96f67c4fe63c543a3ba488 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 17 Feb 2021 21:51:35 -0500 Subject: [PATCH 04/26] create ipv4 and ipv6 NTCP2 addresses separately --- libi2pd/RouterContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 1cfc71db..66c6e6d7 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -98,7 +98,7 @@ namespace i2p if (ntcp2) { if (ntcp2Published) - m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v4::from_string (host), port); + routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v4::from_string (host), port); else // add non-published NTCP2 address routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); } From 616f0b2a21c3b96b900ae01e2c44f2639f35871e Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 19 Feb 2021 15:15:58 -0500 Subject: [PATCH 05/26] address parameter for server tunnels --- libi2pd_client/ClientContext.cpp | 3 ++- libi2pd_client/I2PTunnel.cpp | 27 ++++++++++++++++++++++++++- libi2pd_client/I2PTunnel.h | 6 +++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index cac472f9..eb35b403 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -750,12 +750,13 @@ namespace client else // regular server tunnel by default serverTunnel = std::make_shared (name, host, port, localDestination, inPort, gzip); + if (!address.empty ()) + serverTunnel->SetLocalAddress (address); if(!isUniqueLocal) { LogPrint(eLogInfo, "Clients: disabling loopback address mapping"); serverTunnel->SetUniqueLocal(isUniqueLocal); } - if (accessList.length () > 0) { std::set idents; diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 61c42b24..4cf1031d 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -107,6 +107,18 @@ namespace client } } + void I2PTunnelConnection::Connect (const boost::asio::ip::address& localAddress) + { + if (m_Socket) + { + boost::system::error_code ec; + m_Socket->bind (boost::asio::ip::tcp::endpoint (localAddress, 0), ec); + if (ec) + LogPrint (eLogError, "I2PTunnel: can't bind to ", localAddress.to_string (), ": ", ec.message ()); + } + Connect (false); + } + void I2PTunnelConnection::Terminate () { if (Kill()) return; @@ -600,6 +612,16 @@ namespace client m_IsAccessList = true; } + void I2PServerTunnel::SetLocalAddress (const std::string& localAddress) + { + boost::system::error_code ec; + auto addr = boost::asio::ip::address::from_string(localAddress, ec); + if (!ec) + m_LocalAddress.reset (new boost::asio::ip::address (addr)); + else + LogPrint (eLogError, "I2PTunnel: can't set local address ", localAddress); + } + void I2PServerTunnel::Accept () { if (m_PortDestination) @@ -631,7 +653,10 @@ namespace client // new connection auto conn = CreateI2PConnection (stream); AddHandler (conn); - conn->Connect (m_IsUniqueLocal); + if (m_LocalAddress) + conn->Connect (*m_LocalAddress); + else + conn->Connect (m_IsUniqueLocal); } } diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index f7185dfd..3b52ea1a 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -48,7 +48,8 @@ namespace client ~I2PTunnelConnection (); void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0); void Connect (bool isUniqueLocal = true); - + void Connect (const boost::asio::ip::address& localAddress); + protected: void Terminate (); @@ -314,6 +315,8 @@ namespace client void SetUniqueLocal (bool isUniqueLocal) { m_IsUniqueLocal = isUniqueLocal; } bool IsUniqueLocal () const { return m_IsUniqueLocal; } + void SetLocalAddress (const std::string& localAddress); + const std::string& GetAddress() const { return m_Address; } int GetPort () const { return m_Port; }; uint16_t GetLocalPort () const { return m_PortDestination->GetLocalPort (); }; @@ -339,6 +342,7 @@ namespace client std::shared_ptr m_PortDestination; std::set m_AccessList; bool m_IsAccessList; + std::unique_ptr m_LocalAddress; }; class I2PServerTunnelHTTP: public I2PServerTunnel From 2d972752ff9c4d6a777bed1451bfbeb24349a75e Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 21 Feb 2021 16:20:57 -0500 Subject: [PATCH 06/26] lookuplocal --- libi2pd_client/BOB.cpp | 17 +++++++++++++++++ libi2pd_client/BOB.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/libi2pd_client/BOB.cpp b/libi2pd_client/BOB.cpp index c4447808..69c516d2 100644 --- a/libi2pd_client/BOB.cpp +++ b/libi2pd_client/BOB.cpp @@ -645,6 +645,22 @@ namespace client localDestination->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, requstCallback); } + void BOBCommandSession::LookupLocalCommandHandler (const char * operand, size_t len) + { + LogPrint (eLogDebug, "BOB: lookup local ", operand); + auto addr = context.GetAddressBook ().GetAddress (operand); + if (!addr) + { + SendReplyError ("Address Not found"); + return; + } + auto ls = i2p::data::netdb.FindLeaseSet (addr->identHash); + if (ls) + SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ()); + else + SendReplyError ("Local LeaseSet Not found"); + } + void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len) { LogPrint (eLogDebug, "BOB: clear"); @@ -770,6 +786,7 @@ namespace client m_CommandHandlers[BOB_COMMAND_INPORT] = &BOBCommandSession::InportCommandHandler; m_CommandHandlers[BOB_COMMAND_QUIET] = &BOBCommandSession::QuietCommandHandler; m_CommandHandlers[BOB_COMMAND_LOOKUP] = &BOBCommandSession::LookupCommandHandler; + m_CommandHandlers[BOB_COMMAND_LOOKUP_LOCAL] = &BOBCommandSession::LookupLocalCommandHandler; m_CommandHandlers[BOB_COMMAND_CLEAR] = &BOBCommandSession::ClearCommandHandler; m_CommandHandlers[BOB_COMMAND_LIST] = &BOBCommandSession::ListCommandHandler; m_CommandHandlers[BOB_COMMAND_OPTION] = &BOBCommandSession::OptionCommandHandler; diff --git a/libi2pd_client/BOB.h b/libi2pd_client/BOB.h index 74418011..f5f0c8ee 100644 --- a/libi2pd_client/BOB.h +++ b/libi2pd_client/BOB.h @@ -42,6 +42,7 @@ namespace client const char BOB_COMMAND_INPORT[] = "inport"; const char BOB_COMMAND_QUIET[] = "quiet"; const char BOB_COMMAND_LOOKUP[] = "lookup"; + const char BOB_COMMAND_LOOKUP_LOCAL[] = "lookuplocal"; const char BOB_COMMAND_CLEAR[] = "clear"; const char BOB_COMMAND_LIST[] = "list"; const char BOB_COMMAND_OPTION[] = "option"; @@ -206,6 +207,7 @@ namespace client void InportCommandHandler (const char * operand, size_t len); void QuietCommandHandler (const char * operand, size_t len); void LookupCommandHandler (const char * operand, size_t len); + void LookupLocalCommandHandler (const char * operand, size_t len); void ClearCommandHandler (const char * operand, size_t len); void ListCommandHandler (const char * operand, size_t len); void OptionCommandHandler (const char * operand, size_t len); From 1d7639b3f47f212036e094a7797aa3c04bb4ae95 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 22 Feb 2021 21:04:26 -0500 Subject: [PATCH 07/26] caps per address --- libi2pd/NetDb.cpp | 2 +- libi2pd/RouterInfo.cpp | 59 ++++++++++++++++++++++++++++++------------ libi2pd/RouterInfo.h | 11 +++++--- libi2pd/SSU.cpp | 8 +++--- libi2pd/SSU.h | 2 +- libi2pd/Transports.cpp | 2 +- 6 files changed, 57 insertions(+), 27 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 0222ccdf..66d15cae 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1150,7 +1150,7 @@ namespace data return GetRandomRouter ( [v4only](std::shared_ptr router)->bool { - return !router->IsHidden () && router->IsPeerTesting () && router->IsSSU (v4only); + return !router->IsHidden () && router->IsPeerTesting (v4only); }); } diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 424f23c5..de641602 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -215,6 +215,7 @@ namespace data } else address->transportStyle = eTransportUnknown; + address->caps = 0; address->port = 0; uint16_t size, r = 0; s.read ((char *)&size, sizeof (size)); if (!s) return; @@ -250,7 +251,7 @@ namespace data LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP"); } else if (!strcmp (key, "caps")) - ExtractCaps (value); + address->caps = ExtractCaps (value); else if (!strcmp (key, "s")) // ntcp2 static key { Base64ToByteStream (value, strlen (value), address->ntcp2->staticKey, 32); @@ -353,7 +354,7 @@ namespace data // extract caps if (!strcmp (key, "caps")) - ExtractCaps (value); + m_Caps = ExtractCaps (value); // extract version else if (!strcmp (key, ROUTER_INFO_PROPERTY_VERSION)) { @@ -402,44 +403,46 @@ namespace data return m_Family == fam; } - void RouterInfo::ExtractCaps (const char * value) + uint8_t RouterInfo::ExtractCaps (const char * value) { + uint8_t caps = 0; const char * cap = value; while (*cap) { switch (*cap) { case CAPS_FLAG_FLOODFILL: - m_Caps |= Caps::eFloodfill; + caps |= Caps::eFloodfill; break; case CAPS_FLAG_HIGH_BANDWIDTH1: case CAPS_FLAG_HIGH_BANDWIDTH2: case CAPS_FLAG_HIGH_BANDWIDTH3: - m_Caps |= Caps::eHighBandwidth; + caps |= Caps::eHighBandwidth; break; case CAPS_FLAG_EXTRA_BANDWIDTH1: case CAPS_FLAG_EXTRA_BANDWIDTH2: - m_Caps |= Caps::eExtraBandwidth | Caps::eHighBandwidth; + caps |= Caps::eExtraBandwidth | Caps::eHighBandwidth; break; case CAPS_FLAG_HIDDEN: - m_Caps |= Caps::eHidden; + caps |= Caps::eHidden; break; case CAPS_FLAG_REACHABLE: - m_Caps |= Caps::eReachable; + caps |= Caps::eReachable; break; case CAPS_FLAG_UNREACHABLE: - m_Caps |= Caps::eUnreachable; + caps |= Caps::eUnreachable; break; case CAPS_FLAG_SSU_TESTING: - m_Caps |= Caps::eSSUTesting; + caps |= Caps::eSSUTesting; break; case CAPS_FLAG_SSU_INTRODUCER: - m_Caps |= Caps::eSSUIntroducer; + caps |= Caps::eSSUIntroducer; break; default: ; } cap++; } + return caps; } void RouterInfo::UpdateCapsProperty () @@ -496,8 +499,8 @@ namespace data WriteString ("caps", properties); properties << '='; std::string caps; - if (IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING; - if (IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER; + if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING; + if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER; WriteString (caps, properties); properties << ';'; } @@ -721,7 +724,8 @@ namespace data 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->cost = 10; // NTCP2 should have priority over SSU + addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC; addr->date = 0; addr->ssu.reset (new SSUExt ()); addr->ssu->mtu = mtu; @@ -745,6 +749,7 @@ namespace data addr->port = port; addr->transportStyle = eTransportNTCP; addr->cost = port ? 3 : 14; // override from RouterContext::PublishNTCP2Address + addr->caps = 0; addr->date = 0; addr->ntcp2.reset (new NTCP2Ext ()); if (port) addr->ntcp2->isPublished = true; @@ -794,8 +799,7 @@ namespace data void RouterInfo::SetCaps (const char * caps) { SetProperty ("caps", caps); - m_Caps = 0; - ExtractCaps (caps); + m_Caps = ExtractCaps (caps); } void RouterInfo::SetProperty (const std::string& key, const std::string& value) @@ -1020,5 +1024,28 @@ namespace data return IsReachable () && m_Version >= NETDB_MIN_FLOODFILL_VERSION && GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1; } + + bool RouterInfo::IsPeerTesting (bool v4only) const + { + auto supportedTransports = m_SupportedTransports & (eSSUV4 | eSSUV6); + if (!supportedTransports) return false; // no SSU + if (v4only && !(supportedTransports & eSSUV4)) return false; // no SSU v4 + return GetAddress ( + [](std::shared_ptr address)->bool + { + return (address->transportStyle == eTransportSSU) && address->IsPeerTesting (); + }) != nullptr; + } + + bool RouterInfo::IsIntroducer () const + { + // TODO: support ipv6 + if (!(m_SupportedTransports & eSSUV4)) return false; + return GetAddress ( + [](std::shared_ptr address)->bool + { + return (address->transportStyle == eTransportSSU) && address->IsIntroducer (); + }) != nullptr; + } } } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index c712545e..af8dd8bd 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -111,7 +111,7 @@ namespace data boost::asio::ip::address host; int port; uint64_t date; - uint8_t cost; + uint8_t cost, caps; std::unique_ptr ssu; // not null for SSU std::unique_ptr ntcp2; // not null for NTCP2 @@ -134,6 +134,9 @@ namespace data bool IsNTCP2 () const { return (bool)ntcp2; }; bool IsPublishedNTCP2 () const { return IsNTCP2 () && ntcp2->isPublished; }; + + bool IsIntroducer () const { return caps & eSSUIntroducer; }; + bool IsPeerTesting () const { return caps & eSSUTesting; }; }; typedef std::list > Addresses; @@ -183,12 +186,12 @@ namespace data bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; bool HasValidAddresses () const { return m_SupportedTransports; }; bool UsesIntroducer () const; - bool IsIntroducer () const { return m_Caps & eSSUIntroducer; }; - bool IsPeerTesting () const { return m_Caps & eSSUTesting; }; bool IsHidden () const { return m_Caps & eHidden; }; bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; }; bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; }; bool IsEligibleFloodfill () const; + bool IsPeerTesting (bool v4only) const; + bool IsIntroducer () const; uint8_t GetCaps () const { return m_Caps; }; void SetCaps (uint8_t caps); @@ -231,7 +234,7 @@ namespace data void WriteToStream (std::ostream& s) const; size_t ReadString (char* str, size_t len, std::istream& s) const; void WriteString (const std::string& str, std::ostream& s) const; - void ExtractCaps (const char * value); + uint8_t ExtractCaps (const char * value); template std::shared_ptr GetAddress (Filter filter) const; void UpdateCapsProperty (); diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 79b4f35f..b1d5b77c 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -442,21 +442,21 @@ namespace transport { auto address = router->GetSSUAddress (v4only || !context.SupportsV6 ()); if (address) - CreateSession (router, address->host, address->port, peerTest); + CreateSession (router, address, peerTest); else LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address"); } void SSUServer::CreateSession (std::shared_ptr router, - const boost::asio::ip::address& addr, int port, bool peerTest) + std::shared_ptr address, bool peerTest) { - if (router) + if (router && address) { if (router->UsesIntroducer ()) m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, peerTest)); // always V4 thread else { - boost::asio::ip::udp::endpoint remoteEndpoint (addr, port); + boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); m_Service.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest)); } } diff --git a/libi2pd/SSU.h b/libi2pd/SSU.h index d20f1c9d..bce50a22 100644 --- a/libi2pd/SSU.h +++ b/libi2pd/SSU.h @@ -54,7 +54,7 @@ namespace transport void Stop (); void CreateSession (std::shared_ptr router, bool peerTest = false, bool v4only = false); void CreateSession (std::shared_ptr router, - const boost::asio::ip::address& addr, int port, bool peerTest = false); + std::shared_ptr address, bool peerTest = false); void CreateDirectSession (std::shared_ptr router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest); std::shared_ptr FindSession (std::shared_ptr router) const; std::shared_ptr FindSession (const boost::asio::ip::udp::endpoint& e) const; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 6bed627f..bb79dfdc 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -455,7 +455,7 @@ namespace transport } if (address) { - m_SSUServer->CreateSession (peer.router, address->host, address->port); + m_SSUServer->CreateSession (peer.router, address); return true; } } From b60ebfe1c6f112dde5a53f5743d584717f9d4676 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 22 Feb 2021 22:53:25 -0500 Subject: [PATCH 08/26] parse '4' and '6' address caps --- libi2pd/RouterInfo.cpp | 77 +++++++++++++++++++++++++++--------------- libi2pd/RouterInfo.h | 19 ++++++++--- 2 files changed, 63 insertions(+), 33 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index de641602..bdb2fd03 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -186,6 +186,7 @@ namespace data void RouterInfo::ReadFromStream (std::istream& s) { + m_Caps = 0; s.read ((char *)&m_Timestamp, sizeof (m_Timestamp)); m_Timestamp = be64toh (m_Timestamp); // read addresses @@ -251,7 +252,7 @@ namespace data LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP"); } else if (!strcmp (key, "caps")) - address->caps = ExtractCaps (value); + address->caps = ExtractAddressCaps (value); else if (!strcmp (key, "s")) // ntcp2 static key { Base64ToByteStream (value, strlen (value), address->ntcp2->staticKey, 32); @@ -354,7 +355,7 @@ namespace data // extract caps if (!strcmp (key, "caps")) - m_Caps = ExtractCaps (value); + ExtractCaps (value); // extract version else if (!strcmp (key, ROUTER_INFO_PROPERTY_VERSION)) { @@ -403,7 +404,41 @@ namespace data return m_Family == fam; } - uint8_t RouterInfo::ExtractCaps (const char * value) + void RouterInfo::ExtractCaps (const char * value) + { + const char * cap = value; + while (*cap) + { + switch (*cap) + { + case CAPS_FLAG_FLOODFILL: + m_Caps |= Caps::eFloodfill; + break; + case CAPS_FLAG_HIGH_BANDWIDTH1: + case CAPS_FLAG_HIGH_BANDWIDTH2: + case CAPS_FLAG_HIGH_BANDWIDTH3: + m_Caps |= Caps::eHighBandwidth; + break; + case CAPS_FLAG_EXTRA_BANDWIDTH1: + case CAPS_FLAG_EXTRA_BANDWIDTH2: + m_Caps |= Caps::eExtraBandwidth | Caps::eHighBandwidth; + break; + case CAPS_FLAG_HIDDEN: + m_Caps |= Caps::eHidden; + break; + case CAPS_FLAG_REACHABLE: + m_Caps |= Caps::eReachable; + break; + case CAPS_FLAG_UNREACHABLE: + m_Caps |= Caps::eUnreachable; + break; + default: ; + } + cap++; + } + } + + uint8_t RouterInfo::ExtractAddressCaps (const char * value) const { uint8_t caps = 0; const char * cap = value; @@ -411,32 +446,17 @@ namespace data { switch (*cap) { - case CAPS_FLAG_FLOODFILL: - caps |= Caps::eFloodfill; - break; - case CAPS_FLAG_HIGH_BANDWIDTH1: - case CAPS_FLAG_HIGH_BANDWIDTH2: - case CAPS_FLAG_HIGH_BANDWIDTH3: - caps |= Caps::eHighBandwidth; - break; - case CAPS_FLAG_EXTRA_BANDWIDTH1: - case CAPS_FLAG_EXTRA_BANDWIDTH2: - caps |= Caps::eExtraBandwidth | Caps::eHighBandwidth; - break; - case CAPS_FLAG_HIDDEN: - caps |= Caps::eHidden; - break; - case CAPS_FLAG_REACHABLE: - caps |= Caps::eReachable; - break; - case CAPS_FLAG_UNREACHABLE: - caps |= Caps::eUnreachable; - break; + case CAPS_FLAG_V4: + caps |= AddressCaps::eV4; + break; + case CAPS_FLAG_V6: + caps |= AddressCaps::eV6; + break; case CAPS_FLAG_SSU_TESTING: - caps |= Caps::eSSUTesting; + caps |= AddressCaps::eSSUTesting; break; case CAPS_FLAG_SSU_INTRODUCER: - caps |= Caps::eSSUIntroducer; + caps |= AddressCaps::eSSUIntroducer; break; default: ; } @@ -444,7 +464,7 @@ namespace data } return caps; } - + void RouterInfo::UpdateCapsProperty () { std::string caps; @@ -799,7 +819,8 @@ namespace data void RouterInfo::SetCaps (const char * caps) { SetProperty ("caps", caps); - m_Caps = ExtractCaps (caps); + m_Caps = 0; + ExtractCaps (caps); } void RouterInfo::SetProperty (const std::string& key, const std::string& value) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index af8dd8bd..855f16f1 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -44,6 +44,8 @@ namespace data const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */ const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */ + const char CAPS_FLAG_V4 = '4'; + const char CAPS_FLAG_V6 = '6'; const char CAPS_FLAG_SSU_TESTING = 'B'; const char CAPS_FLAG_SSU_INTRODUCER = 'C'; @@ -67,12 +69,18 @@ namespace data eHighBandwidth = 0x02, eExtraBandwidth = 0x04, eReachable = 0x08, - eSSUTesting = 0x10, - eSSUIntroducer = 0x20, - eHidden = 0x40, - eUnreachable = 0x80 + eHidden = 0x10, + eUnreachable = 0x20 }; + enum AddressCaps + { + eV4 = 0x01, + eV6 = 0x02, + eSSUTesting = 0x04, + eSSUIntroducer = 0x08 + }; + enum TransportStyle { eTransportUnknown = 0, @@ -234,7 +242,8 @@ namespace data void WriteToStream (std::ostream& s) const; size_t ReadString (char* str, size_t len, std::istream& s) const; void WriteString (const std::string& str, std::ostream& s) const; - uint8_t ExtractCaps (const char * value); + void ExtractCaps (const char * value); + uint8_t ExtractAddressCaps (const char * value) const; template std::shared_ptr GetAddress (Filter filter) const; void UpdateCapsProperty (); From c3a2fca76a3b69a3a5b45d7c7a9b7446ceee9191 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 23 Feb 2021 19:59:35 -0500 Subject: [PATCH 09/26] 4 or 6 caps for non-published addresses --- libi2pd/RouterInfo.cpp | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index bdb2fd03..a49ce9ba 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -311,7 +311,15 @@ namespace data supportedTransports |= eNTCP2V4; } else if (!address->ntcp2->isPublished) - supportedTransports |= eNTCP2V4; // most likely, since we don't have host + { + if (address->caps) + { + if (address->caps | AddressCaps::eV4) supportedTransports |= eNTCP2V4; + if (address->caps | AddressCaps::eV6) supportedTransports |= eNTCP2V6; + } + else + supportedTransports |= eNTCP2V4; // most likely, since we don't have host + } } } else if (address->transportStyle == eTransportSSU) @@ -505,10 +513,26 @@ namespace data s.write ((const char *)&address.cost, sizeof (address.cost)); s.write ((const char *)&address.date, sizeof (address.date)); std::stringstream properties; + bool isPublished = false; if (address.transportStyle == eTransportNTCP) { if (address.IsNTCP2 ()) + { WriteString ("NTCP2", s); + if (address.IsPublishedNTCP2 ()) + isPublished = true; + else + { + WriteString ("caps", properties); + properties << '='; + std::string caps; + if (address.caps & AddressCaps::eV4) caps += CAPS_FLAG_V4; + if (address.caps & AddressCaps::eV6) caps += CAPS_FLAG_V6; + if (caps.empty ()) caps += CAPS_FLAG_V4; + WriteString (caps, properties); + properties << ';'; + } + } else continue; // don't write NTCP address } @@ -521,13 +545,17 @@ namespace data std::string caps; if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING; if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER; + if (address.ssu && address.ssu->introducers.empty ()) + isPublished = true; + else + caps += CAPS_FLAG_V4; WriteString (caps, properties); properties << ';'; } else WriteString ("", s); - if (!address.IsNTCP2 () || address.IsPublishedNTCP2 ()) + if (isPublished) { WriteString ("host", properties); properties << '='; @@ -537,7 +565,7 @@ namespace data if (address.transportStyle == eTransportSSU) { // write introducers if any - if (address.ssu->introducers.size () > 0) + if (!address.ssu->introducers.empty()) { int i = 0; for (const auto& introducer: address.ssu->introducers) @@ -616,7 +644,7 @@ namespace data WriteString (address.ntcp2->iv.ToBase64 (), properties); properties << ';'; } - if (!address.IsNTCP2 () || address.IsPublishedNTCP2 ()) + if (isPublished) { WriteString ("port", properties); properties << '='; From 124c3ef2d7092582bd2210773f2dd864ce5be0e0 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 23 Feb 2021 21:15:17 -0500 Subject: [PATCH 10/26] always publish SSU port --- libi2pd/RouterInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index a49ce9ba..751aec10 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -644,7 +644,7 @@ namespace data WriteString (address.ntcp2->iv.ToBase64 (), properties); properties << ';'; } - if (isPublished) + if (isPublished || address.ssu) { WriteString ("port", properties); properties << '='; From a4dda304d214f95f1d84d8b63fe38827e1b74bfa Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 24 Feb 2021 10:03:23 -0500 Subject: [PATCH 11/26] cancel connect timer upon SessionConfirmed --- libi2pd/SSUSession.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index b4f2fcdb..8db317ed 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -321,6 +321,7 @@ namespace transport void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len) { LogPrint (eLogDebug, "SSU: Session confirmed received"); + m_ConnectTimer.cancel (); auto headerSize = GetSSUHeaderSize (buf); if (headerSize >= len) { From 3d7e93a68894554d9f26e7c1a74a1860134d3809 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 25 Feb 2021 00:37:41 +0300 Subject: [PATCH 12/26] systemd: use SIGTERM instead SIGQUIT, indent UPNP code, make client target Signed-off-by: R4SAS --- Makefile | 2 ++ contrib/i2pd.service | 7 ++++++- daemon/UPnP.cpp | 40 ++++++++++++++++++++-------------------- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 3e0b23cf..7357f220 100644 --- a/Makefile +++ b/Makefile @@ -66,6 +66,7 @@ mk_obj_dir: @mkdir -p obj/$(DAEMON_SRC_DIR) api: mk_obj_dir $(SHLIB) $(ARLIB) +client: mk_obj_dir $(SHLIB_CLIENT) $(ARLIB_CLIENT) api_client: mk_obj_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) ## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time @@ -128,6 +129,7 @@ doxygen: .PHONY: last-dist .PHONY: api .PHONY: api_client +.PHONY: client .PHONY: mk_obj_dir .PHONY: install .PHONY: strip diff --git a/contrib/i2pd.service b/contrib/i2pd.service index 8ce851b0..45fe4cc6 100644 --- a/contrib/i2pd.service +++ b/contrib/i2pd.service @@ -17,7 +17,12 @@ PIDFile=/run/i2pd/i2pd.pid ### Uncomment, if auto restart needed #Restart=on-failure -KillSignal=SIGQUIT +# Use SIGTERM to stop i2pd immediately. +# Some cleanup processes can delay stopping, so we set 30 seconds timeout and then SIGKILL i2pd. +KillSignal=SIGTERM +TimeoutStopSec=30s +SendSIGKILL=yes + # If you have the patience waiting 10 min on restarting/stopping it, uncomment this. # i2pd stops accepting new tunnels and waits ~10 min while old ones do not die. #KillSignal=SIGINT diff --git a/daemon/UPnP.cpp b/daemon/UPnP.cpp index 6ea33c46..25e24bb5 100644 --- a/daemon/UPnP.cpp +++ b/daemon/UPnP.cpp @@ -81,10 +81,10 @@ namespace transport void UPnP::Discover () { bool isError; - int err; + int err; #if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS)) - err = UPNPDISCOVER_SUCCESS; + err = UPNPDISCOVER_SUCCESS; #if (MINIUPNPC_API_VERSION >= 14) m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0, 0, 2, &err); @@ -94,8 +94,8 @@ namespace transport isError = err != UPNPDISCOVER_SUCCESS; #else // MINIUPNPC_API_VERSION >= 8 - err = 0; - m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0); + err = 0; + m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0); isError = m_Devlist == NULL; #endif // MINIUPNPC_API_VERSION >= 8 { @@ -106,15 +106,15 @@ namespace transport if (isError) { - LogPrint (eLogError, "UPnP: unable to discover Internet Gateway Devices: error ", err); + LogPrint (eLogError, "UPnP: unable to discover Internet Gateway Devices: error ", err); return; } err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); - m_upnpUrlsInitialized=err!=0; + m_upnpUrlsInitialized=err!=0; if (err == UPNP_IGD_VALID_CONNECTED) { - err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); + err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); if(err != UPNPCOMMAND_SUCCESS) { LogPrint (eLogError, "UPnP: unable to get external address: error ", err); @@ -125,14 +125,14 @@ namespace transport LogPrint (eLogError, "UPnP: found Internet Gateway Device ", m_upnpUrls.controlURL); if (!m_externalIPAddress[0]) { - LogPrint (eLogError, "UPnP: found Internet Gateway Device doesn't know our external address"); + LogPrint (eLogError, "UPnP: found Internet Gateway Device doesn't know our external address"); return; } } } else { - LogPrint (eLogError, "UPnP: unable to find valid Internet Gateway Device: error ", err); + LogPrint (eLogError, "UPnP: unable to find valid Internet Gateway Device: error ", err); return; } @@ -183,7 +183,7 @@ namespace transport err = CheckMapping (strPort.c_str (), strType.c_str ()); if (err != UPNPCOMMAND_SUCCESS) // if mapping not found { - LogPrint (eLogDebug, "UPnP: possibly port ", strPort, " is not forwarded: return code ", err); + LogPrint (eLogDebug, "UPnP: possibly port ", strPort, " is not forwarded: return code ", err); #if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS)) err = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), NULL, NULL); @@ -203,7 +203,7 @@ namespace transport } else { - LogPrint (eLogDebug, "UPnP: external forward from ", m_NetworkAddr, ":", strPort, " exists on current Internet Gateway Device"); + LogPrint (eLogDebug, "UPnP: external forward from ", m_NetworkAddr, ":", strPort, " exists on current Internet Gateway Device"); return; } } @@ -220,14 +220,14 @@ namespace transport void UPnP::CloseMapping (std::shared_ptr address) { - if(!m_upnpUrlsInitialized) { - return; - } + if(!m_upnpUrlsInitialized) { + return; + } std::string strType (GetProto (address)), strPort (std::to_string (address->port)); int err = UPNPCOMMAND_SUCCESS; err = CheckMapping (strPort.c_str (), strType.c_str ()); - if (err == UPNPCOMMAND_SUCCESS) + if (err == UPNPCOMMAND_SUCCESS) { err = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), NULL); LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", err); @@ -238,11 +238,11 @@ namespace transport { freeUPNPDevlist (m_Devlist); m_Devlist = 0; - if(m_upnpUrlsInitialized){ - FreeUPNPUrls (&m_upnpUrls); - m_upnpUrlsInitialized=false; - } - } + if(m_upnpUrlsInitialized){ + FreeUPNPUrls (&m_upnpUrls); + m_upnpUrlsInitialized=false; + } + } std::string UPnP::GetProto (std::shared_ptr address) { From f75bef7c039800da29dd731e976c324ddbc906ed Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 24 Feb 2021 18:40:24 -0500 Subject: [PATCH 13/26] don't set local address if not specified --- libi2pd_client/ClientContext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index eb35b403..2f3d4d48 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -691,7 +691,7 @@ namespace client i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL); - std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); + std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, ""); bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); // I2CP @@ -718,6 +718,7 @@ namespace client { // udp server tunnel // TODO: hostnames + if (address.empty ()) address = "127.0.0.1"; auto localAddress = boost::asio::ip::address::from_string(address); boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port); auto serverTunnel = std::make_shared(name, localDestination, localAddress, endpoint, port, gzip); From 4371a084ec3ba14e046de3e286ff5fcc855c92dd Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 26 Feb 2021 03:20:06 +0300 Subject: [PATCH 14/26] check for pubkey in X25519Keys::Agree Signed-off-by: R4SAS --- libi2pd/Crypto.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 68850a9d..14ef83ae 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -353,7 +353,7 @@ namespace crypto bool X25519Keys::Agree (const uint8_t * pub, uint8_t * shared) { - if (pub[31] & 0x80) return false; // not x25519 key + if (!pub || (pub[31] & 0x80)) return false; // not x25519 key #if OPENSSL_X25519 EVP_PKEY_derive_init (m_Ctx); auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32); From fbe83f729d9a76fba11ee37d20e3dc084416b478 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 25 Feb 2021 19:55:46 -0500 Subject: [PATCH 15/26] don't try to send to unreachable router --- libi2pd/Transports.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index bb79dfdc..5848fd16 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -351,7 +351,7 @@ namespace transport try { auto r = netdb.FindRouter (ident); - if (!r || !r->IsCompatible (i2p::context.GetRouterInfo ())) return; + if (!r || r->IsUnreachable () || !r->IsCompatible (i2p::context.GetRouterInfo ())) return; { std::unique_lock l(m_PeersMutex); it = m_Peers.insert (std::pair(ident, { 0, r, {}, From 2cdf84cdaba9089e32d37fef598a9f26577b17e7 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 26 Feb 2021 21:09:01 +0000 Subject: [PATCH 16/26] [actions] upload windows artifacts --- .github/workflows/build-windows.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index c979e43f..83b68d71 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -29,3 +29,7 @@ jobs: run: | mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon make USE_UPNP=yes DEBUG=no -j3 + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + path: i2pd.exe From a4e8bf985798b43fae5aa87e4fff8f2a21b9810d Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 26 Feb 2021 19:31:38 -0500 Subject: [PATCH 17/26] bind NTCP2 connections to specified address --- libi2pd/Config.cpp | 4 +++- libi2pd/NTCP2.cpp | 32 ++++++++++++++++++++++++++++++++ libi2pd/NTCP2.h | 5 ++++- libi2pd/Transports.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 9da0bbe0..cc79c87c 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -50,7 +50,9 @@ namespace config { ("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") ("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)") + ("address4", value()->default_value(""), "Local address to bind ipv4 transport sockets to") ("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)") + ("address6", value()->default_value(""), "Local address to bind ipv6 transport sockets to") ("reservedrange", bool_switch()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)") ("netid", value()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") ("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)") @@ -247,7 +249,7 @@ namespace config { ("ntcp2.enabled", value()->default_value(true), "Enable NTCP2 (default: enabled)") ("ntcp2.published", value()->default_value(true), "Publish NTCP2 (default: enabled)") ("ntcp2.port", value()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)") - ("ntcp2.addressv6", value()->default_value("::"), "Address to bind NTCP2 on") + ("ntcp2.addressv6", value()->default_value("::"), "Address to publish NTCP2 with") ("ntcp2.proxy", value()->default_value(""), "Proxy URL for NTCP2 transport") ; diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 61e766ea..078c5045 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1291,6 +1291,24 @@ namespace transport conn->Terminate (); } }); + // bind to local address + std::shared_ptr localAddress; + if (conn->GetRemoteEndpoint ().address ().is_v6 ()) + { + if (i2p::util::net::IsYggdrasilAddress (conn->GetRemoteEndpoint ().address ())) + localAddress = m_YggdrasilAddress; + else + localAddress = m_Address6; + } + else + localAddress = m_Address4; + if (localAddress) + { + boost::system::error_code ec; + conn->GetSocket ().bind (*localAddress, ec); + if (ec) + LogPrint (eLogError, "NTCP2: can't bind to ", localAddress->address ().to_string (), ": ", ec.message ()); + } conn->GetSocket ().async_connect (conn->GetRemoteEndpoint (), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer)); } else @@ -1631,5 +1649,19 @@ namespace transport conn->Terminate(); }); } + + void NTCP2Server::SetLocalAddress (const boost::asio::ip::address& localAddress) + { + auto addr = std::make_shared(boost::asio::ip::tcp::endpoint(localAddress, 0)); + if (localAddress.is_v6 ()) + { + if (i2p::util::net::IsYggdrasilAddress (localAddress)) + m_YggdrasilAddress = addr; + else + m_Address6 = addr; + } + else + m_Address4 = addr; + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index c3909225..23b619e8 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -248,6 +248,8 @@ namespace transport bool UsingProxy() const { return m_ProxyType != eNoProxy; }; void UseProxy(ProxyType proxy, const std::string & address, uint16_t port); + void SetLocalAddress (const boost::asio::ip::address& localAddress); + private: void HandleAccept (std::shared_ptr conn, const boost::system::error_code& error); @@ -273,7 +275,8 @@ namespace transport uint16_t m_ProxyPort; boost::asio::ip::tcp::resolver m_Resolver; std::unique_ptr m_ProxyEndpoint; - + std::shared_ptr m_Address4, m_Address6, m_YggdrasilAddress; + public: // for HTTP/I2PControl diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 5848fd16..09b0991a 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -205,6 +205,46 @@ namespace transport } } + // bind to interfaces + bool ipv4; i2p::config::GetOption("ipv4", ipv4); + if (ipv4) + { + std::string address; i2p::config::GetOption("address4", address); + if (!address.empty ()) + { + boost::system::error_code ec; + auto addr = boost::asio::ip::address::from_string (address, ec); + if (!ec && m_NTCP2Server) + m_NTCP2Server->SetLocalAddress (addr); + } + } + + bool ipv6; i2p::config::GetOption("ipv6", ipv6); + if (ipv6) + { + std::string address; i2p::config::GetOption("address6", address); + if (!address.empty ()) + { + boost::system::error_code ec; + auto addr = boost::asio::ip::address::from_string (address, ec); + if (!ec && m_NTCP2Server) + m_NTCP2Server->SetLocalAddress (addr); + } + } + + bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); + if (ygg) + { + std::string address; i2p::config::GetOption("meshnets.yggdrasil", address); + if (!address.empty ()) + { + boost::system::error_code ec; + auto addr = boost::asio::ip::address::from_string (address, ec); + if (!ec && m_NTCP2Server && i2p::util::net::IsYggdrasilAddress (addr)) + m_NTCP2Server->SetLocalAddress (addr); + } + } + // create acceptors auto& addresses = context.GetRouterInfo ().GetAddresses (); for (const auto& address : addresses) From fab53dda66eaaad42c49729dc7bdb7e56b56cf39 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 26 Feb 2021 20:38:16 -0500 Subject: [PATCH 18/26] fixed typo --- libi2pd/Transports.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 09b0991a..4d1e49a4 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -235,7 +235,7 @@ namespace transport bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); if (ygg) { - std::string address; i2p::config::GetOption("meshnets.yggdrasil", address); + std::string address; i2p::config::GetOption("meshnets.yggaddress", address); if (!address.empty ()) { boost::system::error_code ec; From 40f7e9d33e824ccfb0801805c9d6217d96ea27ce Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 26 Feb 2021 21:02:51 -0500 Subject: [PATCH 19/26] separate decryptor for tunnel builds and floodfill requests --- libi2pd/RouterContext.cpp | 13 +++++++------ libi2pd/RouterContext.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 66c6e6d7..33b5077b 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -41,6 +41,7 @@ namespace i2p if (!Load ()) CreateNewRouter (); m_Decryptor = m_Keys.CreateDecryptor (nullptr); + m_TunnelDecryptor = m_Keys.CreateDecryptor (nullptr); UpdateRouterInfo (); if (IsECIES ()) { @@ -105,7 +106,7 @@ namespace i2p if (ssu) { routerInfo.AddSSUAddress (host.c_str(), port, nullptr); - caps |= i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // R, BC + caps |= i2p::data::RouterInfo::eReachable; // R } } if (ipv6) @@ -424,7 +425,6 @@ namespace i2p caps &= ~i2p::data::RouterInfo::eReachable; caps |= i2p::data::RouterInfo::eUnreachable; caps &= ~i2p::data::RouterInfo::eFloodfill; // can't be floodfill - caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer m_RouterInfo.SetCaps (caps); uint16_t port = 0; // delete previous introducers @@ -432,6 +432,7 @@ namespace i2p for (auto& addr : addresses) if (addr->ssu) { + addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer addr->ssu->introducers.clear (); port = addr->port; } @@ -449,7 +450,6 @@ namespace i2p uint8_t caps = m_RouterInfo.GetCaps (); caps &= ~i2p::data::RouterInfo::eUnreachable; caps |= i2p::data::RouterInfo::eReachable; - caps |= i2p::data::RouterInfo::eSSUIntroducer; if (m_IsFloodfill) caps |= i2p::data::RouterInfo::eFloodfill; m_RouterInfo.SetCaps (caps); @@ -459,6 +459,7 @@ namespace i2p for (auto& addr : addresses) if (addr->ssu) { + addr->caps |= i2p::data::RouterInfo::eSSUIntroducer; addr->ssu->introducers.clear (); port = addr->port; } @@ -771,7 +772,7 @@ namespace i2p bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) { - if (!m_Decryptor) return false; + if (!m_TunnelDecryptor) return false; if (IsECIES ()) { if (!m_InitialNoiseState) return false; @@ -779,7 +780,7 @@ namespace i2p m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState)); m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk) uint8_t sharedSecret[32]; - if (!m_Decryptor->Decrypt (encrypted, sharedSecret, ctx, false)) + if (!m_TunnelDecryptor->Decrypt (encrypted, sharedSecret, ctx, false)) { LogPrint (eLogWarning, "Router: Incorrect ephemeral public key"); return false; @@ -798,7 +799,7 @@ namespace i2p return true; } else - return m_Decryptor->Decrypt (encrypted, data, ctx, false); + return m_TunnelDecryptor->Decrypt (encrypted, data, ctx, false); } i2p::crypto::X25519Keys& RouterContext::GetStaticKeys () diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 12b77d65..3c8e6d9d 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -153,7 +153,7 @@ namespace i2p i2p::data::RouterInfo m_RouterInfo; i2p::data::PrivateKeys m_Keys; - std::shared_ptr m_Decryptor; + std::shared_ptr m_Decryptor, m_TunnelDecryptor; uint64_t m_LastUpdateTime; // in seconds bool m_AcceptsTunnels, m_IsFloodfill; std::chrono::time_point m_StartupTime; From 288b19c3f7099d18fdc2711b258ba8e345421cbc Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 27 Feb 2021 10:35:50 -0500 Subject: [PATCH 20/26] bind NTCP2 ipv4 acceptor to specified local address --- libi2pd/NTCP2.cpp | 8 +++++- libi2pd/Transports.cpp | 64 +++++++++++++++++++++--------------------- 2 files changed, 39 insertions(+), 33 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 078c5045..96a52b15 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1170,7 +1170,9 @@ namespace transport { try { - m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port))); + auto ep = m_Address4 ? boost::asio::ip::tcp::endpoint (m_Address4->address(), address->port): + boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), address->port); + m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), ep)); } catch ( std::exception & ex ) { @@ -1299,9 +1301,13 @@ namespace transport localAddress = m_YggdrasilAddress; else localAddress = m_Address6; + conn->GetSocket ().open (boost::asio::ip::tcp::v6 ()); } else + { localAddress = m_Address4; + conn->GetSocket ().open (boost::asio::ip::tcp::v4 ()); + } if (localAddress) { boost::system::error_code ec; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 4d1e49a4..c44672ec 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -189,7 +189,6 @@ namespace transport proxytype = NTCP2Server::eHTTPProxy; m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port); - m_NTCP2Server->Start(); } else LogPrint(eLogError, "Transports: unsupported NTCP2 proxy URL ", ntcp2proxy); @@ -199,12 +198,38 @@ namespace transport return; } else - { m_NTCP2Server = new NTCP2Server (); - m_NTCP2Server->Start (); - } } + // create acceptors + auto& addresses = context.GetRouterInfo ().GetAddresses (); + for (const auto& address : addresses) + { + if (!address) continue; + if (address->transportStyle == RouterInfo::eTransportSSU) + { + if (m_SSUServer == nullptr && enableSSU) + { + if (address->host.is_v4()) + m_SSUServer = new SSUServer (address->port); + else + m_SSUServer = new SSUServer (address->host, address->port); + LogPrint (eLogInfo, "Transports: Start listening UDP port ", address->port); + try { + m_SSUServer->Start (); + } catch ( std::exception & ex ) { + LogPrint(eLogError, "Transports: Failed to bind to UDP port", address->port); + delete m_SSUServer; + m_SSUServer = nullptr; + continue; + } + DetectExternalIP (); + } + else + LogPrint (eLogError, "Transports: SSU server already exists"); + } + } + // bind to interfaces bool ipv4; i2p::config::GetOption("ipv4", ipv4); if (ipv4) @@ -244,35 +269,10 @@ namespace transport m_NTCP2Server->SetLocalAddress (addr); } } + + // start servers + if (m_NTCP2Server) m_NTCP2Server->Start (); - // create acceptors - auto& addresses = context.GetRouterInfo ().GetAddresses (); - for (const auto& address : addresses) - { - if (!address) continue; - if (address->transportStyle == RouterInfo::eTransportSSU) - { - if (m_SSUServer == nullptr && enableSSU) - { - if (address->host.is_v4()) - m_SSUServer = new SSUServer (address->port); - else - m_SSUServer = new SSUServer (address->host, address->port); - LogPrint (eLogInfo, "Transports: Start listening UDP port ", address->port); - try { - m_SSUServer->Start (); - } catch ( std::exception & ex ) { - LogPrint(eLogError, "Transports: Failed to bind to UDP port", address->port); - delete m_SSUServer; - m_SSUServer = nullptr; - continue; - } - DetectExternalIP (); - } - else - LogPrint (eLogError, "Transports: SSU server already exists"); - } - } m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); From bef9a54f4ae646783356a5155855e5724cdea2be Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 27 Feb 2021 16:13:12 -0500 Subject: [PATCH 21/26] bind SSU socket to specified address --- libi2pd/SSU.cpp | 36 +++++++++-------------- libi2pd/SSU.h | 5 ++-- libi2pd/Transports.cpp | 66 ++++++++++++++++++++++++------------------ 3 files changed, 54 insertions(+), 53 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index b1d5b77c..06e8d075 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -22,21 +22,8 @@ namespace i2p { namespace transport { - - SSUServer::SSUServer (const boost::asio::ip::address & addr, int port): - m_OnlyV6(true), m_IsRunning(false), m_Thread (nullptr), - m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service), - m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6), - m_EndpointV6 (addr, port), m_Socket (m_ReceiversService, m_Endpoint), - m_SocketV6 (m_ReceiversServiceV6), m_IntroducersUpdateTimer (m_Service), - m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service), - m_TerminationTimerV6 (m_Service) - { - OpenSocketV6 (); - } - SSUServer::SSUServer (int port): - m_OnlyV6(false), m_IsRunning(false), m_Thread (nullptr), + m_IsRunning(false), m_Thread (nullptr), m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6), m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port), @@ -44,9 +31,6 @@ namespace transport m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service) { - OpenSocket (); - if (context.SupportsV6 ()) - OpenSocketV6 (); } SSUServer::~SSUServer () @@ -91,18 +75,18 @@ namespace transport void SSUServer::Start () { m_IsRunning = true; - if (!m_OnlyV6) + m_Thread = new std::thread (std::bind (&SSUServer::Run, this)); + if (context.SupportsV4 ()) { - m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this)); - m_Thread = new std::thread (std::bind (&SSUServer::Run, this)); + OpenSocket (); + m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this)); m_ReceiversService.post (std::bind (&SSUServer::Receive, this)); ScheduleTermination (); } if (context.SupportsV6 ()) { + OpenSocketV6 (); m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this)); - if (!m_Thread) - m_Thread = new std::thread (std::bind (&SSUServer::Run, this)); m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this)); ScheduleTerminationV6 (); } @@ -205,6 +189,14 @@ namespace transport } } + void SSUServer::SetLocalAddress (const boost::asio::ip::address& localAddress) + { + if (localAddress.is_v6 ()) + m_EndpointV6.address (localAddress); + else if (localAddress.is_v4 ()) + m_Endpoint.address (localAddress); + } + void SSUServer::AddRelay (uint32_t tag, std::shared_ptr relay) { m_Relays[tag] = relay; diff --git a/libi2pd/SSU.h b/libi2pd/SSU.h index bce50a22..648d760c 100644 --- a/libi2pd/SSU.h +++ b/libi2pd/SSU.h @@ -48,7 +48,6 @@ namespace transport public: SSUServer (int port); - SSUServer (const boost::asio::ip::address & addr, int port); // ipv6 only constructor ~SSUServer (); void Start (); void Stop (); @@ -64,7 +63,8 @@ namespace transport void DeleteAllSessions (); boost::asio::io_service& GetService () { return m_Service; }; - const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; + void SetLocalAddress (const boost::asio::ip::address& localAddress); + void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); void AddRelay (uint32_t tag, std::shared_ptr relay); void RemoveRelay (uint32_t tag); @@ -118,7 +118,6 @@ namespace transport std::shared_ptr session; // for Bob to Alice }; - bool m_OnlyV6; volatile bool m_IsRunning; std::thread * m_Thread, * m_ReceiversThread, * m_ReceiversThreadV6; boost::asio::io_service m_Service, m_ReceiversService, m_ReceiversServiceV6; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index c44672ec..705754f0 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -201,34 +201,22 @@ namespace transport m_NTCP2Server = new NTCP2Server (); } - // create acceptors - auto& addresses = context.GetRouterInfo ().GetAddresses (); - for (const auto& address : addresses) - { - if (!address) continue; - if (address->transportStyle == RouterInfo::eTransportSSU) + // create SSU server + int ssuPort = 0; + if (enableSSU) + { + auto& addresses = context.GetRouterInfo ().GetAddresses (); + for (const auto& address: addresses) { - if (m_SSUServer == nullptr && enableSSU) + if (!address) continue; + if (address->transportStyle == RouterInfo::eTransportSSU) { - if (address->host.is_v4()) - m_SSUServer = new SSUServer (address->port); - else - m_SSUServer = new SSUServer (address->host, address->port); - LogPrint (eLogInfo, "Transports: Start listening UDP port ", address->port); - try { - m_SSUServer->Start (); - } catch ( std::exception & ex ) { - LogPrint(eLogError, "Transports: Failed to bind to UDP port", address->port); - delete m_SSUServer; - m_SSUServer = nullptr; - continue; - } - DetectExternalIP (); + ssuPort = address->port; + m_SSUServer = new SSUServer (address->port); + break; } - else - LogPrint (eLogError, "Transports: SSU server already exists"); } - } + } // bind to interfaces bool ipv4; i2p::config::GetOption("ipv4", ipv4); @@ -239,8 +227,11 @@ namespace transport { boost::system::error_code ec; auto addr = boost::asio::ip::address::from_string (address, ec); - if (!ec && m_NTCP2Server) - m_NTCP2Server->SetLocalAddress (addr); + if (!ec) + { + if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr); + if (m_SSUServer) m_SSUServer->SetLocalAddress (addr); + } } } @@ -252,8 +243,11 @@ namespace transport { boost::system::error_code ec; auto addr = boost::asio::ip::address::from_string (address, ec); - if (!ec && m_NTCP2Server) - m_NTCP2Server->SetLocalAddress (addr); + if (!ec) + { + if (m_NTCP2Server) m_NTCP2Server->SetLocalAddress (addr); + if (m_SSUServer) m_SSUServer->SetLocalAddress (addr); + } } } @@ -272,6 +266,22 @@ namespace transport // start servers if (m_NTCP2Server) m_NTCP2Server->Start (); + if (m_SSUServer) + { + LogPrint (eLogInfo, "Transports: Start listening UDP port ", ssuPort); + try + { + m_SSUServer->Start (); + } + catch (std::exception& ex ) + { + LogPrint(eLogError, "Transports: Failed to bind to UDP port", ssuPort); + m_SSUServer->Stop (); + delete m_SSUServer; + m_SSUServer = nullptr; + } + if (m_SSUServer) DetectExternalIP (); + } m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); From 8bab4f60ef833d1718293c2c559e00d0cc5afc09 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 28 Feb 2021 09:04:34 -0500 Subject: [PATCH 22/26] open socket before bing --- libi2pd_client/I2PTunnel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libi2pd_client/I2PTunnel.cpp b/libi2pd_client/I2PTunnel.cpp index 4cf1031d..b15b47b0 100644 --- a/libi2pd_client/I2PTunnel.cpp +++ b/libi2pd_client/I2PTunnel.cpp @@ -111,6 +111,10 @@ namespace client { if (m_Socket) { + if (m_RemoteEndpoint.address().is_v6 ()) + m_Socket->open (boost::asio::ip::tcp::v6 ()); + else + m_Socket->open (boost::asio::ip::tcp::v4 ()); boost::system::error_code ec; m_Socket->bind (boost::asio::ip::tcp::endpoint (localAddress, 0), ec); if (ec) From 11c924bbe75b3fd7a09097cc7be2bad188428a63 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 28 Feb 2021 18:58:25 -0500 Subject: [PATCH 23/26] publish and handle SSU addreses without host --- libi2pd/RouterInfo.cpp | 4 +- libi2pd/SSU.cpp | 123 ++++++++++++++++++++--------------------- libi2pd/SSU.h | 3 +- 3 files changed, 64 insertions(+), 66 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 751aec10..f683cc2d 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -329,7 +329,7 @@ namespace data if (isHost) supportedTransports |= address->host.is_v4 () ? eSSUV4 : eSSUV6; else - if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented + if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented } } if (supportedTransports) @@ -545,7 +545,7 @@ namespace data std::string caps; if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU_TESTING; if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER; - if (address.ssu && address.ssu->introducers.empty ()) + if (IsReachable ()) isPublished = true; else caps += CAPS_FLAG_V4; diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 06e8d075..be5ac9c7 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -445,7 +445,7 @@ namespace transport if (router && address) { if (router->UsesIntroducer ()) - m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, peerTest)); // always V4 thread + m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, address, peerTest)); // always V4 thread else { boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); @@ -477,13 +477,13 @@ namespace transport } } - void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr router, bool peerTest) + void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr router, + std::shared_ptr address, bool peerTest) { - if (router && router->UsesIntroducer ()) - { - auto address = router->GetSSUAddress (true); // v4 only for now - if (address) - { + if (router && router->UsesIntroducer () && address) + { + if (!address->host.is_unspecified () && address->port) + { boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); auto it = m_Sessions.find (remoteEndpoint); // check if session is presented already @@ -494,70 +494,67 @@ namespace transport session->SendPeerTest (); return; } - // create new session - int numIntroducers = address->ssu->introducers.size (); - if (numIntroducers > 0) + } + // create new session + int numIntroducers = address->ssu->introducers.size (); + if (numIntroducers > 0) + { + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + std::shared_ptr introducerSession; + const i2p::data::RouterInfo::Introducer * introducer = nullptr; + // we might have a session to introducer already + for (int i = 0; i < numIntroducers; i++) { - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - std::shared_ptr introducerSession; - const i2p::data::RouterInfo::Introducer * introducer = nullptr; - // we might have a session to introducer already - for (int i = 0; i < numIntroducers; i++) + auto intr = &(address->ssu->introducers[i]); + if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer + boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort); + if (ep.address ().is_v4 ()) // ipv4 only { - auto intr = &(address->ssu->introducers[i]); - if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer - boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort); - if (ep.address ().is_v4 ()) // ipv4 only + if (!introducer) introducer = intr; // we pick first one for now + auto it = m_Sessions.find (ep); + if (it != m_Sessions.end ()) { - if (!introducer) introducer = intr; // we pick first one for now - it = m_Sessions.find (ep); - if (it != m_Sessions.end ()) - { - introducerSession = it->second; - break; - } + introducerSession = it->second; + break; } } - if (!introducer) - { - LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no ipv4 non-expired introducers presented"); - return; - } - - if (introducerSession) // session found - LogPrint (eLogWarning, "SSU: Session to introducer already exists"); - else // create new - { - LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost); - boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort); - introducerSession = std::make_shared (*this, introducerEndpoint, router); - m_Sessions[introducerEndpoint] = introducerSession; - } -#if BOOST_VERSION >= 104900 - if (!address->host.is_unspecified () && address->port) -#endif - { - // create session - auto session = std::make_shared (*this, remoteEndpoint, router, peerTest); - m_Sessions[remoteEndpoint] = session; - - // introduce - LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), - "] through introducer ", introducer->iHost, ":", introducer->iPort); - session->WaitForIntroduction (); - if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable - { - uint8_t buf[1]; - Send (buf, 0, remoteEndpoint); // send HolePunch - } - } - introducerSession->Introduce (*introducer, router); } - else - LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present"); + if (!introducer) + { + LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no ipv4 non-expired introducers presented"); + return; + } + + if (introducerSession) // session found + LogPrint (eLogWarning, "SSU: Session to introducer already exists"); + else // create new + { + LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost); + boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort); + introducerSession = std::make_shared (*this, introducerEndpoint, router); + m_Sessions[introducerEndpoint] = introducerSession; + } + if (!address->host.is_unspecified () && address->port) + { + // create session + boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); + auto session = std::make_shared (*this, remoteEndpoint, router, peerTest); + m_Sessions[remoteEndpoint] = session; + + // introduce + LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), + "] through introducer ", introducer->iHost, ":", introducer->iPort); + session->WaitForIntroduction (); + if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable + { + uint8_t buf[1]; + Send (buf, 0, remoteEndpoint); // send HolePunch + } + } + introducerSession->Introduce (*introducer, router); } else - LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address"); + LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present"); } } diff --git a/libi2pd/SSU.h b/libi2pd/SSU.h index 648d760c..b674e8ac 100644 --- a/libi2pd/SSU.h +++ b/libi2pd/SSU.h @@ -90,7 +90,8 @@ namespace transport void HandleReceivedPackets (std::vector packets, std::map >* sessions); - void CreateSessionThroughIntroducer (std::shared_ptr router, bool peerTest = false); + void CreateSessionThroughIntroducer (std::shared_ptr router, + std::shared_ptr address, bool peerTest = false); template std::shared_ptr GetRandomV4Session (Filter filter); template From ae58a7007b9f1aadffbdce3898752e2f2245c27c Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 28 Feb 2021 19:19:09 -0500 Subject: [PATCH 24/26] different cost for direct or with introducers SSU address --- libi2pd/RouterContext.cpp | 2 ++ libi2pd/RouterInfo.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 33b5077b..6c5d3405 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -432,6 +432,7 @@ namespace i2p for (auto& addr : addresses) if (addr->ssu) { + addr->cost = 11; addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer addr->ssu->introducers.clear (); port = addr->port; @@ -459,6 +460,7 @@ namespace i2p for (auto& addr : addresses) if (addr->ssu) { + addr->cost = 9; addr->caps |= i2p::data::RouterInfo::eSSUIntroducer; addr->ssu->introducers.clear (); port = addr->port; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index f683cc2d..c73800df 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -772,7 +772,7 @@ namespace data addr->host = boost::asio::ip::address::from_string (host); addr->port = port; addr->transportStyle = eTransportSSU; - addr->cost = 10; // NTCP2 should have priority over SSU + addr->cost = 9; // NTCP2 should have priority over SSU addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC; addr->date = 0; addr->ssu.reset (new SSUExt ()); From 57c969b0eda9c12248acab015e8c0782f19b3577 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 1 Mar 2021 11:09:25 -0500 Subject: [PATCH 25/26] constants for cost --- libi2pd/RouterContext.cpp | 6 +++--- libi2pd/RouterInfo.cpp | 4 ++-- libi2pd/RouterInfo.h | 5 +++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 6c5d3405..a7273376 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -224,7 +224,7 @@ namespace i2p if (port == 9150) port = 9151; // Tor browser } if (port) address->port = port; - address->cost = publish ? 3 : 14; + address->cost = publish ? i2p::data::COST_NTCP2_PUBLISHED : i2p::data::COST_NTCP2_NON_PUBLISHED; address->ntcp2->isPublished = publish; address->ntcp2->iv = m_NTCP2Keys->iv; updated = true; @@ -432,7 +432,7 @@ namespace i2p for (auto& addr : addresses) if (addr->ssu) { - addr->cost = 11; + addr->cost = i2p::data::COST_SSU_THROUGH_INTRODUCERS; addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer addr->ssu->introducers.clear (); port = addr->port; @@ -460,7 +460,7 @@ namespace i2p for (auto& addr : addresses) if (addr->ssu) { - addr->cost = 9; + addr->cost = i2p::data::COST_SSU_DIRECT; addr->caps |= i2p::data::RouterInfo::eSSUIntroducer; addr->ssu->introducers.clear (); port = addr->port; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index c73800df..4ea66add 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -772,7 +772,7 @@ namespace data addr->host = boost::asio::ip::address::from_string (host); addr->port = port; addr->transportStyle = eTransportSSU; - addr->cost = 9; // NTCP2 should have priority over SSU + addr->cost = COST_SSU_DIRECT; // NTCP2 should have priority over SSU addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC; addr->date = 0; addr->ssu.reset (new SSUExt ()); @@ -796,7 +796,7 @@ namespace data addr->host = host; addr->port = port; addr->transportStyle = eTransportNTCP; - addr->cost = port ? 3 : 14; // override from RouterContext::PublishNTCP2Address + addr->cost = port ? COST_NTCP2_PUBLISHED : COST_NTCP2_NON_PUBLISHED; // override from RouterContext::PublishNTCP2Address addr->caps = 0; addr->date = 0; addr->ntcp2.reset (new NTCP2Ext ()); diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 855f16f1..9e9f00cd 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -49,6 +49,11 @@ namespace data const char CAPS_FLAG_SSU_TESTING = 'B'; const char CAPS_FLAG_SSU_INTRODUCER = 'C'; + const uint8_t COST_NTCP2_PUBLISHED = 3; + const uint8_t COST_NTCP2_NON_PUBLISHED = 14; + const uint8_t COST_SSU_DIRECT = 9; + const uint8_t COST_SSU_THROUGH_INTRODUCERS = 11; + const int MAX_RI_BUFFER_SIZE = 2048; // if RouterInfo exceeds 2048 we consider it as malformed, might be changed later class RouterInfo: public RoutingDestination { From 6d88c3ab05d573ff9ff3bef22f4deee3f6208a1d Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 1 Mar 2021 12:20:53 -0500 Subject: [PATCH 26/26] Symmetric NAT error --- daemon/HTTPServer.cpp | 3 +++ libi2pd/RouterContext.h | 3 ++- libi2pd/SSU.h | 1 + libi2pd/SSUSession.cpp | 2 ++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 0847f85d..89960e0c 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -263,6 +263,9 @@ namespace http { case eRouterErrorOffline: s << " - Offline"; break; + case eRouterErrorSymmetricNAT: + s << " - Symmetric NAT"; + break; default: ; } break; diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 3c8e6d9d..228da788 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -39,7 +39,8 @@ namespace i2p { eRouterErrorNone = 0, eRouterErrorClockSkew = 1, - eRouterErrorOffline = 2 + eRouterErrorOffline = 2, + eRouterErrorSymmetricNAT = 3 }; class RouterContext: public i2p::garlic::GarlicDestination diff --git a/libi2pd/SSU.h b/libi2pd/SSU.h index b674e8ac..bfcfed4e 100644 --- a/libi2pd/SSU.h +++ b/libi2pd/SSU.h @@ -63,6 +63,7 @@ namespace transport void DeleteAllSessions (); boost::asio::io_service& GetService () { return m_Service; }; + uint16_t GetPort () const { return m_Endpoint.port (); }; void SetLocalAddress (const boost::asio::ip::address& localAddress); void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 8db317ed..e1e48b75 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -684,6 +684,8 @@ namespace transport buf += 2; // our port LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort); i2p::context.UpdateAddress (ourIP); + if (ourPort != m_Server.GetPort ()) + i2p::context.SetError (eRouterErrorSymmetricNAT); uint32_t nonce = bufbe32toh (buf); buf += 4; // nonce auto it = m_RelayRequests.find (nonce);