diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index cfb92f00..38fd46ce 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -178,52 +178,56 @@ namespace i2p } if (ipv6) { - std::string host; i2p::config::GetOption("address6", host); - if (host.empty () && !ipv4) i2p::config::GetOption("host", host); // use host for ipv6 only if ipv4 is not presented + auto ipv6addr = i2p::util::net::GetClearnetIPV6Address (); + if (!ipv6addr.is_unspecified ()) + { + std::string host; i2p::config::GetOption("address6", host); + if (host.empty () && !ipv4) i2p::config::GetOption("host", host); // use host for ipv6 only if ipv4 is not presented - if (ntcp2) - { - uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port); - if (!ntcp2Port) ntcp2Port = port; - if (ntcp2Published && ntcp2Port) + if (ntcp2) { - std::string ntcp2Host; - if (!i2p::config::IsDefault ("ntcp2.addressv6")) - i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host); + uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port); + if (!ntcp2Port) ntcp2Port = port; + if (ntcp2Published && ntcp2Port) + { + std::string ntcp2Host; + if (!i2p::config::IsDefault ("ntcp2.addressv6")) + i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host); + else + ntcp2Host = host; + boost::asio::ip::address addr; + if (!ntcp2Host.empty ()) + addr = boost::asio::ip::make_address (ntcp2Host); + if (!addr.is_v6()) + addr = boost::asio::ip::address_v6 (); + routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port); + } else - ntcp2Host = host; - boost::asio::ip::address addr; - if (!ntcp2Host.empty ()) - addr = boost::asio::ip::make_address (ntcp2Host); - if (!addr.is_v6()) - addr = boost::asio::ip::address_v6 (); - routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port); + { + if (!ipv4) // no other ntcp2 addresses yet + routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::AddressCaps::eV6); + } } - else + if (ssu2) { - if (!ipv4) // no other ntcp2 addresses yet - routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::AddressCaps::eV6); + uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); + if (!ssu2Port) ssu2Port = port; + if (ssu2Published && ssu2Port) + { + boost::asio::ip::address addr; + if (!host.empty ()) + addr = boost::asio::ip::make_address (host); + if (!addr.is_v6()) + addr = boost::asio::ip::address_v6 (); + routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port); + } + else + { + if (!ipv4) // no other ssu2 addresses yet + routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::AddressCaps::eV6); + } } - } - if (ssu2) - { - uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); - if (!ssu2Port) ssu2Port = port; - if (ssu2Published && ssu2Port) - { - boost::asio::ip::address addr; - if (!host.empty ()) - addr = boost::asio::ip::make_address (host); - if (!addr.is_v6()) - addr = boost::asio::ip::address_v6 (); - routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port); - } - else - { - if (!ipv4) // no other ssu2 addresses yet - routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::AddressCaps::eV6); - } - } + } } if (ygg) { diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 98dbcd94..6c9e699a 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -1345,6 +1345,12 @@ namespace transport } } + if (ipv6 && i2p::util::net::GetClearnetIPV6Address ().is_unspecified ()) + { + LogPrint(eLogWarning, "Transports: Clearnet ipv6 not found. Disabled"); + ipv6 = false; + } + if (!i2p::config::IsDefault("port")) { LogPrint(eLogInfo, "Transports: Accepting incoming connections at port ", port); diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 0bd19d23..9fd6ac23 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -545,7 +545,8 @@ namespace net return (reservedPorts.find(port) != reservedPorts.end()); } - boost::asio::ip::address_v6 GetYggdrasilAddress () + template + static boost::asio::ip::address_v6 GetLocalIPV6Address (CheckAddress checkAddress) { #if defined(_WIN32) ULONG outBufLen = 0; @@ -580,7 +581,7 @@ namespace net { LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr; - if (IsYggdrasilAddress(localInterfaceAddress->sin6_addr.u.Byte)) { + if (checkAddress(localInterfaceAddress->sin6_addr.u.Byte)) { boost::asio::ip::address_v6::bytes_type bytes; memcpy (bytes.data (), &localInterfaceAddress->sin6_addr.u.Byte, 16); FREE(pAddresses); @@ -590,7 +591,7 @@ namespace net } pCurrAddresses = pCurrAddresses->Next; } - LogPrint(eLogWarning, "NetIface: Interface with Yggdrasil network address not found"); + LogPrint(eLogWarning, "NetIface: Interface with ipv6 network address not found"); FREE(pAddresses); return boost::asio::ip::address_v6 (); #else @@ -604,7 +605,7 @@ namespace net if (cur->ifa_addr && cur->ifa_addr->sa_family == AF_INET6) { sockaddr_in6* sa = (sockaddr_in6*)cur->ifa_addr; - if (IsYggdrasilAddress(sa->sin6_addr.s6_addr)) + if (checkAddress(sa->sin6_addr.s6_addr)) { boost::asio::ip::address_v6::bytes_type bytes; memcpy (bytes.data (), &sa->sin6_addr, 16); @@ -617,14 +618,27 @@ namespace net } catch (std::exception& ex) { - LogPrint(eLogError, "NetIface: Exception while searching Yggdrasill address using ifaddr: ", ex.what()); + LogPrint(eLogError, "NetIface: Exception while searching ipv6 address using ifaddr: ", ex.what()); } - LogPrint(eLogWarning, "NetIface: Interface with Yggdrasil network address not found"); + LogPrint(eLogWarning, "NetIface: Interface with ipv6 network address not found"); if (addrs) freeifaddrs(addrs); return boost::asio::ip::address_v6 (); #endif } + boost::asio::ip::address_v6 GetYggdrasilAddress () + { + return GetLocalIPV6Address ([](const uint8_t addr[16]) { return IsYggdrasilAddress (addr); }); + } + + boost::asio::ip::address_v6 GetClearnetIPV6Address () + { + return GetLocalIPV6Address ([](const uint8_t addr[16]) + { + return (addr[0] & 0xF0) == 0x20; // 2000::/3 + }); + } + bool IsLocalAddress (const boost::asio::ip::address& addr) { auto mtu = // TODO: implement better diff --git a/libi2pd/util.h b/libi2pd/util.h index 7bd35e67..683a2b1f 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -231,6 +231,7 @@ namespace util int GetMaxMTU (const boost::asio::ip::address_v6& localAddress); // check tunnel broker for ipv6 address const boost::asio::ip::address GetInterfaceAddress (const std::string & ifname, bool ipv6=false); boost::asio::ip::address_v6 GetYggdrasilAddress (); + boost::asio::ip::address_v6 GetClearnetIPV6Address (); bool IsLocalAddress (const boost::asio::ip::address& addr); bool IsInReservedRange (const boost::asio::ip::address& host); bool IsYggdrasilAddress (const boost::asio::ip::address& addr);