Skip to content
2 changes: 2 additions & 0 deletions contrib/dinit/i2pd
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ smooth-recovery = true
depends-on = ntpd
# uncomment if you want to use i2pd with yggdrasil
# depends-on = yggdrasil
# uncomment if you want to use i2pd with mycelium
# depends-on = mycelium
pid-file = /var/lib/i2pd/i2pd.pid
9 changes: 8 additions & 1 deletion contrib/i2pd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,12 @@ ipv6 = false
## The address must first be added to the network interface
# yggaddress =

## Enable connectivity over the Mycelium network (default: false)
# mycelium = false
## You can bind address from your Mycelium subnet 500::/64
## The address must first be added to the network interface
# mycaddress =

[reseed]
## Options for bootstrapping into I2P network, aka reseeding
## Enable reseed data verification (default: true)
Expand All @@ -230,6 +236,8 @@ verify = true
# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/
## Reseed URLs through the Yggdrasil, separated by comma
# yggurls = http://[324:71e:281a:9ed3::ace]:7070/
## Reseed URLs through the Mycelium, separated by comma
# mycurls =
## Path to local reseed data file (.su3) for manual reseeding
# file = /path/to/i2pseeds.su3
## or HTTPS URL to reseed from
Expand Down Expand Up @@ -280,4 +288,3 @@ verify = true
# profiles = true
## Save full addresses on disk (default: true)
# addressbook = true

5 changes: 5 additions & 0 deletions libi2pd/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ namespace config {
"http://[320:8936:ec1a:31f1::216]/,"
"http://[316:f9e0:f22e:a74f::216]/"
), "Reseed URLs through the Yggdrasil, separated by comma")
("reseed.mycurls", value<std::string>()->default_value(
"" // @TODO
), "Reseed URLs through the Mycelium, separated by comma")
;

options_description addressbook("AddressBook options");
Expand Down Expand Up @@ -356,6 +359,8 @@ namespace config {
meshnets.add_options()
("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (default: false)")
("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish")
("meshnets.mycelium", bool_switch()->default_value(false), "Support transports through the Mycelium (default: false)")
("meshnets.mycaddress", value<std::string>()->default_value(""), "Mycelium address to publish")
;

#ifdef __linux__
Expand Down
25 changes: 18 additions & 7 deletions libi2pd/NTCP2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,17 +847,19 @@ namespace transport
}

auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri1->GetNTCP2V4Address () :
(i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri1->GetYggdrasilAddress () : ri1->GetNTCP2V6Address ());
(i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri1->GetYggdrasilAddress () : (
i2p::util::net::IsMyceliumAddress (m_RemoteEndpoint.address ()) ? ri1->GetMyceliumAddress () : ri1->GetNTCP2V6Address ()));
if (!addr || memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32))
{
LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed");
Terminate ();
return;
}
if (addr->IsPublishedNTCP2 () && m_RemoteEndpoint.address () != addr->host &&
(!m_RemoteEndpoint.address ().is_v6 () || (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ?
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil subnet
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address
(!m_RemoteEndpoint.address ().is_v6 () ||
(i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) || i2p::util::net::IsMyceliumAddress (m_RemoteEndpoint.address ()) ?
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil | mycelium subnet
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address
{
if (isOlder) // older router?
i2p::data::UpdateRouterProfile (ri1->GetIdentHash (),
Expand Down Expand Up @@ -1469,7 +1471,9 @@ namespace transport
i2p::data::RouterInfo::SupportedTransports NTCP2Session::GetTransportType () const
{
if (m_RemoteEndpoint.address ().is_v4 ()) return i2p::data::RouterInfo::eNTCP2V4;
return i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? i2p::data::RouterInfo::eNTCP2V6Mesh : i2p::data::RouterInfo::eNTCP2V6;
return i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ||
i2p::util::net::IsMyceliumAddress (m_RemoteEndpoint.address ()) ? i2p::data::RouterInfo::eNTCP2V6Mesh
: i2p::data::RouterInfo::eNTCP2V6;
}

NTCP2Server::NTCP2Server ():
Expand Down Expand Up @@ -1547,7 +1551,7 @@ namespace transport
m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true));
m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true));
#if defined(__linux__) && !defined(_NETINET_IN_H)
if (!m_Address6 && !m_YggdrasilAddress) // only if not binded to address
if (!m_Address6 && !m_YggdrasilAddress && !m_MyceliumAddress) // only if not binded to address
{
// Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others
#if (BOOST_VERSION >= 105500)
Expand All @@ -1563,6 +1567,8 @@ namespace transport
ep = boost::asio::ip::tcp::endpoint (m_Address6->address(), address->port);
else if (m_YggdrasilAddress && !context.SupportsV6 ())
ep = boost::asio::ip::tcp::endpoint (m_YggdrasilAddress->address(), address->port);
else if (m_MyceliumAddress && !context.SupportsV6 ())
ep = boost::asio::ip::tcp::endpoint (m_MyceliumAddress->address(), address->port);
m_NTCP2V6Acceptor->bind (ep);
m_NTCP2V6Acceptor->listen ();

Expand Down Expand Up @@ -1687,6 +1693,8 @@ namespace transport
{
if (i2p::util::net::IsYggdrasilAddress (conn->GetRemoteEndpoint ().address ()))
localAddress = m_YggdrasilAddress;
else if (i2p::util::net::IsMyceliumAddress (conn->GetRemoteEndpoint ().address ()))
localAddress = m_MyceliumAddress;
else
localAddress = m_Address6;
conn->GetSocket ().open (boost::asio::ip::tcp::v6 ());
Expand Down Expand Up @@ -1783,7 +1791,8 @@ namespace transport
{
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
if (!i2p::transport::transports.IsInReservedRange(ep.address ()) ||
i2p::util::net::IsYggdrasilAddress (ep.address ()))
i2p::util::net::IsYggdrasilAddress (ep.address ()) ||
i2p::util::net::IsMyceliumAddress (ep.address ()))
{
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
{
Expand Down Expand Up @@ -2015,6 +2024,8 @@ namespace transport
{
if (i2p::util::net::IsYggdrasilAddress (localAddress))
m_YggdrasilAddress = addr;
if (i2p::util::net::IsMyceliumAddress (localAddress))
m_MyceliumAddress = addr;
else
m_Address6 = addr;
}
Expand Down
2 changes: 1 addition & 1 deletion libi2pd/NTCP2.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ namespace transport
boost::asio::ip::tcp::resolver m_Resolver;
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;

std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress;
std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress, m_MyceliumAddress;
std::mt19937 m_Rng;
EstablisherService m_EstablisherService;
i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor;
Expand Down
38 changes: 24 additions & 14 deletions libi2pd/Reseed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ namespace data
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
bool yggdrasil; i2p::config::GetOption("meshnets.yggdrasil", yggdrasil);
bool mycelium; i2p::config::GetOption("meshnets.mycelium", mycelium);

std::vector<std::string> httpsReseedHostList;
if (ipv4 || ipv6)
Expand All @@ -98,16 +99,25 @@ namespace data
boost::split(httpsReseedHostList, reseedURLs, boost::is_any_of(","), boost::token_compress_on);
}

std::vector<std::string> yggReseedHostList;
std::vector<std::string> meshReseedHostList;

if (yggdrasil && !i2p::util::net::GetYggdrasilAddress ().is_unspecified ())
{
LogPrint (eLogInfo, "Reseed: Yggdrasil is supported");
std::string yggReseedURLs; i2p::config::GetOption("reseed.yggurls", yggReseedURLs);
if (!yggReseedURLs.empty ())
boost::split(yggReseedHostList, yggReseedURLs, boost::is_any_of(","), boost::token_compress_on);
boost::split(meshReseedHostList, yggReseedURLs, boost::is_any_of(","), boost::token_compress_on);
}

if (mycelium && !i2p::util::net::GetMyceliumAddress ().is_unspecified ())
{
LogPrint (eLogInfo, "Reseed: Mycelium is supported");
std::string mycReseedURLs; i2p::config::GetOption("reseed.mycurls", mycReseedURLs);
if (!mycReseedURLs.empty ())
boost::split(meshReseedHostList, mycReseedURLs, boost::is_any_of(","), boost::token_compress_on);
}

if (httpsReseedHostList.empty () && yggReseedHostList.empty())
if (httpsReseedHostList.empty () && meshReseedHostList.empty())
{
LogPrint (eLogWarning, "Reseed: No reseed servers specified");
return 0;
Expand All @@ -116,10 +126,10 @@ namespace data
int reseedRetries = 0;
while (reseedRetries < 10)
{
auto ind = rand () % (httpsReseedHostList.size () + yggReseedHostList.size ());
auto ind = rand () % (httpsReseedHostList.size () + meshReseedHostList.size ());
bool isHttps = ind < httpsReseedHostList.size ();
std::string reseedUrl = isHttps ? httpsReseedHostList[ind] :
yggReseedHostList[ind - httpsReseedHostList.size ()];
meshReseedHostList[ind - httpsReseedHostList.size ()];
reseedUrl += "i2pseeds.su3";
auto num = ReseedFromSU3Url (reseedUrl, isHttps);
if (num > 0) return num; // success
Expand All @@ -137,7 +147,7 @@ namespace data
int Reseeder::ReseedFromSU3Url (const std::string& url, bool isHttps)
{
LogPrint (eLogInfo, "Reseed: Downloading SU3 from ", url);
std::string su3 = isHttps ? HttpsRequest (url) : YggdrasilRequest (url);
std::string su3 = isHttps ? HttpsRequest (url) : MeshRequest (url);
if (su3.length () > 0)
{
std::stringstream s(su3);
Expand Down Expand Up @@ -669,7 +679,7 @@ namespace data
if (ep.address ().is_v4 ())
supported = i2p::context.SupportsV4 ();
else if (ep.address ().is_v6 ())
supported = i2p::util::net::IsYggdrasilAddress (ep.address ()) ?
supported = i2p::util::net::IsYggdrasilAddress (ep.address ()) || i2p::util::net::IsMyceliumAddress (ep.address ()) ?
i2p::context.SupportsMesh () : i2p::context.SupportsV6 ();
}
if (supported)
Expand Down Expand Up @@ -749,7 +759,7 @@ namespace data
return data;
}

std::string Reseeder::YggdrasilRequest (const std::string& address)
std::string Reseeder::MeshRequest (const std::string& address)
{
i2p::http::URL url;
if (!url.parse(address))
Expand All @@ -772,11 +782,11 @@ namespace data
{
boost::asio::ip::tcp::endpoint ep = it;
if (
i2p::util::net::IsYggdrasilAddress (ep.address ()) &&
i2p::context.SupportsMesh ()
(i2p::util::net::IsYggdrasilAddress (ep.address ()) ||
i2p::util::net::IsMyceliumAddress (ep.address ())) && i2p::context.SupportsMesh ()
)
{
LogPrint (eLogDebug, "Reseed: Yggdrasil: Resolved to ", ep.address ());
LogPrint (eLogDebug, "Reseed: Mesh: Resolved to ", ep.address ());
s.connect (ep, ecode);
if (!ecode)
{
Expand All @@ -787,18 +797,18 @@ namespace data
}
if (!connected)
{
LogPrint(eLogError, "Reseed: Yggdrasil: Failed to connect to ", url.host);
LogPrint(eLogError, "Reseed: Mesh: Failed to connect to ", url.host);
return "";
}
}

if (!ecode)
{
LogPrint (eLogDebug, "Reseed: Yggdrasil: Connected to ", url.host, ":", url.port);
LogPrint (eLogDebug, "Reseed: Mesh: Connected to ", url.host, ":", url.port);
return ReseedRequest (s, url.to_string());
}
else
LogPrint (eLogError, "Reseed: Yggdrasil: Couldn't connect to ", url.host, ": ", ecode.message ());
LogPrint (eLogError, "Reseed: Mesh: Couldn't connect to ", url.host, ": ", ecode.message ());

return "";
}
Expand Down
2 changes: 1 addition & 1 deletion libi2pd/Reseed.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace data
bool FindZipDataDescriptor (std::istream& s);

std::string HttpsRequest (const std::string& address);
std::string YggdrasilRequest (const std::string& address);
std::string MeshRequest (const std::string& address);
template<typename Stream>
std::string ReseedRequest (Stream& s, const std::string& uri);

Expand Down
22 changes: 16 additions & 6 deletions libi2pd/RouterContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,10 @@ namespace i2p
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 myc; i2p::config::GetOption("meshnets.mycelium", myc);
bool nat; i2p::config::GetOption("nat", nat);

if ((ntcp2 || ygg) && !m_NTCP2Keys)
if ((ntcp2 || ygg || myc) && !m_NTCP2Keys)
NewNTCP2Keys ();
if (ssu2 && !m_SSU2Keys)
NewSSU2Keys ();
Expand Down Expand Up @@ -235,6 +236,12 @@ namespace i2p
if (!yggaddr.is_unspecified ())
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, yggaddr, port);
}
if (myc)
{
auto mycaddr = i2p::util::net::GetMyceliumAddress ();
if (!mycaddr.is_unspecified ())
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, mycaddr, port);
}

routerInfo.UpdateCaps (caps); // caps + L
routerInfo.SetProperty ("netId", std::to_string (m_NetID));
Expand Down Expand Up @@ -415,7 +422,7 @@ namespace i2p
memcpy (address->i, m_NTCP2Keys->iv, 16);
}

void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg)
void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool mesh)
{
if (!m_NTCP2Keys) return;
auto addresses = m_RouterInfo.GetAddresses ();
Expand All @@ -439,7 +446,7 @@ namespace i2p
updated = true;
}
}
if (ygg)
if (mesh)
{
auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6MeshIdx];
if (addr && (addr->port != port || addr->published != publish))
Expand Down Expand Up @@ -796,7 +803,9 @@ namespace i2p
{
for (auto& addr: *addresses)
{
if (addr && addr->IsV6 () && !i2p::util::net::IsYggdrasilAddress (addr->host))
if (addr && addr->IsV6 () &&
!i2p::util::net::IsYggdrasilAddress (addr->host) &&
!i2p::util::net::IsMyceliumAddress (addr->host))
{
switch (addr->transportStyle)
{
Expand Down Expand Up @@ -1036,7 +1045,7 @@ namespace i2p
auto addresses = m_RouterInfo.GetAddresses ();
if (!addresses) return;
std::shared_ptr<i2p::data::RouterInfo::Address> addr;
if (i2p::util::net::IsYggdrasilAddress (host)) // yggdrasil
if (i2p::util::net::IsYggdrasilAddress (host) || i2p::util::net::IsMyceliumAddress (host))
addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6MeshIdx];
else if (host.is_v6 ())
addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6Idx];
Expand Down Expand Up @@ -1150,7 +1159,8 @@ namespace i2p
// create new NTCP2 keys if required
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
if ((ntcp2 || ygg) && !m_NTCP2Keys)
bool myc; i2p::config::GetOption("meshnets.mycelium", myc);
if ((ntcp2 || ygg || myc) && !m_NTCP2Keys)
{
NewNTCP2Keys ();
UpdateNTCP2Keys ();
Expand Down
2 changes: 1 addition & 1 deletion libi2pd/RouterContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ namespace garlic

void UpdatePort (int port); // called from Daemon
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU2 or Daemon
void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg);
void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool mesh);
void PublishSSU2Address (int port, bool publish, bool v4, bool v6);
bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4);
void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4);
Expand Down
11 changes: 7 additions & 4 deletions libi2pd/RouterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ namespace data
if (!ecode && !address->host.is_unspecified ())
{
if (!i2p::transport::transports.IsInReservedRange (address->host) ||
i2p::util::net::IsYggdrasilAddress (address->host))
i2p::util::net::IsYggdrasilAddress (address->host) ||
i2p::util::net::IsMyceliumAddress (address->host))
isHost = true;
else
// we consider such address as invalid
Expand Down Expand Up @@ -360,7 +361,8 @@ namespace data
if (isHost && address->port)
{
if (address->host.is_v6 ())
supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) || // OR wants review @TODO
i2p::util::net::IsMyceliumAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
else
supportedTransports |= eNTCP2V4;
m_PublishedTransports |= supportedTransports;
Expand Down Expand Up @@ -717,7 +719,7 @@ namespace data
}
if (addr->IsV6 ())
{
if (i2p::util::net::IsYggdrasilAddress (addr->host))
if (i2p::util::net::IsYggdrasilAddress (addr->host) || i2p::util::net::IsMyceliumAddress (addr->host))
{
m_SupportedTransports |= eNTCP2V6Mesh;
m_ReachableTransports |= eNTCP2V6Mesh;
Expand Down Expand Up @@ -1082,7 +1084,8 @@ namespace data
case eTransportNTCP2:
if (addr->IsV4 ()) transports |= eNTCP2V4;
if (addr->IsV6 ())
transports |= (i2p::util::net::IsYggdrasilAddress (addr->host) ? eNTCP2V6Mesh : eNTCP2V6);
transports |= (i2p::util::net::IsYggdrasilAddress (addr->host) || // OR wants review @TODO
i2p::util::net::IsMyceliumAddress (addr->host) ? eNTCP2V6Mesh : eNTCP2V6);
if (addr->IsPublishedNTCP2 ())
m_ReachableTransports |= transports;
break;
Expand Down
1 change: 1 addition & 0 deletions libi2pd/RouterInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ namespace data
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
std::shared_ptr<const Address> GetYggdrasilAddress () const;
std::shared_ptr<const Address> GetMyceliumAddress () const;
std::shared_ptr<const Address> GetSSU2V4Address () const;
std::shared_ptr<const Address> GetSSU2V6Address () const;
std::shared_ptr<const Address> GetSSU2Address (bool v4) const;
Expand Down
Loading