set source ip on service nodes for outbound link to not use all interfaces

pull/1905/head
Jeff 2 years ago
parent 60ada470db
commit 98b3860655
No known key found for this signature in database
GPG Key ID: 025C02EE3A092F2D

@ -126,32 +126,23 @@ namespace llarp
"provided the public-port option must also be specified.",
},
[this](std::string arg) {
if (not arg.empty())
{
llarp::LogInfo("public ip ", arg, " size ", arg.size());
if (arg.empty())
return;
nuint32_t addr{};
if (not addr.FromString(arg))
throw std::invalid_argument{stringify(arg, " is not a valid IPv4 address")};
if (arg.size() > 15)
throw std::invalid_argument(stringify("Not a valid IPv4 addr: ", arg));
if (IsIPv4Bogon(addr))
throw std::invalid_argument{
stringify(addr, " looks like it is not a publicly routable ip address")};
m_publicAddress.setAddress(arg);
}
m_PublicIP = addr;
});
conf.defineOption<std::string>("router", "public-address", Hidden, [this](std::string arg) {
if (not arg.empty())
{
llarp::LogWarn(
"*** WARNING: The config option [router]:public-address=",
arg,
" is deprecated, use public-ip=",
arg,
" instead to avoid this warning and avoid future configuration problems.");
if (arg.size() > 15)
throw std::invalid_argument(stringify("Not a valid IPv4 addr: ", arg));
m_publicAddress.setAddress(arg);
}
conf.defineOption<std::string>("router", "public-address", Hidden, [](std::string) {
throw std::invalid_argument{
"[router]:public-address option no longer supported, use [router]:public-ip and "
"[router]:public-port instead"};
});
conf.defineOption<int>(
@ -166,8 +157,7 @@ namespace llarp
[this](int arg) {
if (arg <= 0 || arg > std::numeric_limits<uint16_t>::max())
throw std::invalid_argument("public-port must be >= 0 and <= 65536");
m_publicAddress.setPort(arg);
m_PublicPort = ToNet(huint16_t{static_cast<uint16_t>(arg)});
});
conf.defineOption<int>(

@ -54,7 +54,8 @@ namespace llarp
bool m_blockBogons = false;
IpAddress m_publicAddress;
std::optional<nuint32_t> m_PublicIP;
nuint16_t m_PublicPort;
int m_workerThreads = -1;
int m_numNetThreads = -1;

@ -8,6 +8,7 @@
#include <utility>
#include <unordered_set>
#include <llarp/router/abstractrouter.hpp>
#include <oxenc/variant.h>
static constexpr auto LINK_LAYER_TICK_INTERVAL = 100ms;
@ -129,7 +130,7 @@ namespace llarp
}
bool
ILinkLayer::Configure(AbstractRouter* router, const std::string& ifname, int af, uint16_t port)
ILinkLayer::Configure(AbstractRouter* router, std::string ifname, int af, uint16_t port)
{
m_Router = router;
m_udp = m_Router->loop()->make_udp(
@ -142,11 +143,42 @@ namespace llarp
if (ifname == "*")
{
if (!AllInterfaces(af, m_ourAddr))
if (router->IsServiceNode())
{
if (auto maybe = router->OurPublicIP())
{
auto addr = var::visit([](auto&& addr) { return SockAddr{addr}; }, *maybe);
// service node outbound link
if (HasInterfaceAddress(addr.getIP()))
{
// we have our ip claimed on a local net interface
m_ourAddr = addr;
}
else if (auto maybe = net::AllInterfaces(addr))
{
// we do not have our claimed ip, nat or something?
m_ourAddr = *maybe;
}
else
return false; // the ultimate failure case
}
else
return false;
}
else if (auto maybe = net::AllInterfaces(SockAddr{"0.0.0.0"}))
{
// client outbound link
m_ourAddr = *maybe;
}
else
return false;
}
else
{
if (ifname == "0.0.0.0" and not GetBestNetIF(ifname))
throw std::invalid_argument{
"0.0.0.0 provided and we cannot find a valid ip to use, please set one "
"explicitly instead in the bind section instead of 0.0.0.0"};
if (const auto maybe = GetInterfaceAddr(ifname, af))
{
m_ourAddr = *maybe;
@ -157,10 +189,11 @@ namespace llarp
{
m_ourAddr = SockAddr{ifname + ":0"};
}
catch (const std::exception& e)
catch (const std::exception& ex)
{
LogError(stringify("Could not use ifname ", ifname, " to configure ILinkLayer"));
throw e;
LogError(
stringify("Could not use ifname ", ifname, " to configure ILinkLayer: ", ex.what()));
throw ex;
}
}
}

@ -108,7 +108,7 @@ namespace llarp
SendTo_LL(const SockAddr& to, const llarp_buffer_t& pkt);
virtual bool
Configure(AbstractRouter* loop, const std::string& ifname, int af, uint16_t port);
Configure(AbstractRouter* loop, std::string ifname, int af, uint16_t port);
virtual std::shared_ptr<ILinkSession>
NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) = 0;

@ -27,6 +27,12 @@ namespace llarp
return lhs.rank < rhs.rank || lhs.ip < rhs.ip || lhs.port < rhs.port;
}
std::variant<nuint32_t, nuint128_t>
AddressInfo::IP() const
{
return SockAddr{ip}.getIP();
}
bool
AddressInfo::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
{

@ -9,6 +9,8 @@
#include <string>
#include <vector>
#include <oxenc/variant.h>
/**
* address_info.hpp
*
@ -47,6 +49,10 @@ namespace llarp
void
fromSockAddr(const SockAddr& address);
/// get this as an explicit v4 or explicit v6
std::variant<nuint32_t, nuint128_t>
IP() const;
std::ostream&
print(std::ostream& stream, int level, int spaces) const;
};

@ -576,29 +576,56 @@ namespace llarp
return addr.asIPv6();
}
bool
AllInterfaces(int af, SockAddr& result)
namespace net
{
if (af == AF_INET)
namespace
{
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(0);
result = SockAddr{addr};
return true;
}
if (af == AF_INET6)
SockAddr
All(int af)
{
if (af == AF_INET)
{
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(0);
return SockAddr{addr};
}
sockaddr_in6 addr6{};
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(0);
addr6.sin6_addr = IN6ADDR_ANY_INIT;
return SockAddr{addr6};
}
} // namespace
std::optional<SockAddr>
AllInterfaces(SockAddr pub)
{
sockaddr_in6 addr6;
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(0);
addr6.sin6_addr = IN6ADDR_ANY_INIT;
result = SockAddr{addr6};
return true;
std::optional<SockAddr> found;
IterAllNetworkInterfaces([pub, &found](auto* ifa) {
if (found)
return;
if (auto ifa_addr = ifa->ifa_addr)
{
if (ifa_addr->sa_family != pub.Family())
return;
SockAddr addr{*ifa->ifa_addr};
if (addr == pub)
found = addr;
}
});
// 0.0.0.0 is used in our compat shim as our public ip so we check for that special case
const auto zero = IPRange::FromIPv4(0, 0, 0, 0, 8);
// when we cannot find an address but we are looking for 0.0.0.0 just default to the old style
if (not found and (pub.isIPv4() and zero.Contains(pub.asIPv4())))
found = All(pub.Family());
return found;
}
return false;
}
} // namespace net
#if !defined(TESTNET)
static constexpr std::array bogonRanges_v6 = {
@ -692,5 +719,20 @@ namespace llarp
return false;
}
#endif
bool
HasInterfaceAddress(std::variant<nuint32_t, nuint128_t> ip)
{
bool found{false};
IterAllNetworkInterfaces([ip, &found](const auto* iface) {
if (found or iface == nullptr)
return;
if (auto addr = iface->ifa_addr;
addr and (addr->sa_family == AF_INET or addr->sa_family == AF_INET6))
{
found = SockAddr{*iface->ifa_addr}.getIP() == ip;
}
});
return found;
}
} // namespace llarp

@ -52,6 +52,12 @@ namespace llarp
bool
IsIPv4Bogon(const huint32_t& addr);
inline bool
IsIPv4Bogon(const nuint32_t& addr)
{
return IsIPv4Bogon(ToHost(addr));
}
bool
IsBogon(const in6_addr& addr);
@ -61,8 +67,25 @@ namespace llarp
bool
IsBogonRange(const in6_addr& host, const in6_addr& mask);
bool
AllInterfaces(int af, SockAddr& addr);
/// get a sock addr we can use for all interfaces given our public address
namespace net
{
std::optional<SockAddr>
AllInterfaces(SockAddr pubaddr);
}
/// compat shim
// TODO: remove me
inline bool
AllInterfaces(int af, SockAddr& addr)
{
if (auto maybe = net::AllInterfaces(SockAddr{af == AF_INET ? "0.0.0.0" : "::"}))
{
addr = *maybe;
return true;
}
return false;
}
/// get first network interface with public address
bool
@ -92,4 +115,8 @@ namespace llarp
}
#endif
/// return true if we have a network interface with this ip
bool
HasInterfaceAddress(std::variant<nuint32_t, nuint128_t> ip);
} // namespace llarp

@ -351,6 +351,14 @@ namespace llarp
return a;
}
std::variant<nuint32_t, nuint128_t>
SockAddr::getIP() const
{
if (isIPv4())
return getIPv4();
return getIPv6();
}
void
SockAddr::setIPv4(nuint32_t ip)
{

@ -12,6 +12,7 @@
#include <string_view>
#include <string>
#include "net_int.hpp"
#include <oxenc/variant.h>
namespace llarp
{
@ -81,6 +82,14 @@ namespace llarp
std::string
hostString() const;
inline int
Family() const
{
if (isIPv6())
return AF_INET6;
return AF_INET;
}
/// Returns true if this is an empty SockAddr, defined by having no IP address set. An empty IP
/// address with a valid port is still considered empty.
///
@ -133,6 +142,8 @@ namespace llarp
getIPv6() const;
nuint32_t
getIPv4() const;
std::variant<nuint32_t, nuint128_t>
getIP() const;
/// in host order
huint128_t

@ -220,6 +220,10 @@ namespace llarp
virtual const byte_t*
pubkey() const = 0;
/// get what our real public ip is if we can know it
virtual std::optional<std::variant<nuint32_t, nuint128_t>>
OurPublicIP() const = 0;
/// connect to N random routers
virtual void
ConnectToRandomRouters(int N) = 0;

@ -415,9 +415,6 @@ namespace llarp
if (!FromConfig(conf))
throw std::runtime_error("FromConfig() failed");
if (!InitOutboundLinks())
throw std::runtime_error("InitOutboundLinks() failed");
if (not EnsureIdentity())
throw std::runtime_error("EnsureIdentity() failed");
@ -596,8 +593,8 @@ namespace llarp
transport_keyfile = m_keyManager->m_transportKeyPath;
ident_keyfile = m_keyManager->m_idKeyPath;
if (not conf.router.m_publicAddress.isEmpty())
_ourAddress = conf.router.m_publicAddress.createSockAddr();
if (auto maybe = conf.router.m_PublicIP)
_ourAddress = SockAddr{*maybe, conf.router.m_PublicPort};
RouterContact::BlockBogons = conf.router.m_blockBogons;
@ -728,14 +725,15 @@ namespace llarp
if (inboundLinks.empty() and m_isServiceNode)
{
const auto& publicAddr = conf.router.m_publicAddress;
if (publicAddr.isEmpty() or not publicAddr.hasPort())
if (_ourAddress)
{
throw std::runtime_error(
"service node enabled but could not find a public IP to bind to; you need to set the "
"public-ip= and public-port= options");
inboundLinks.push_back(LinksConfig::LinkInfo{
_ourAddress->hostString(), _ourAddress->Family(), _ourAddress->getPort()});
}
inboundLinks.push_back(LinksConfig::LinkInfo{"0.0.0.0", AF_INET, *publicAddr.getPort()});
else
throw std::runtime_error{
"service node enabled but could not find a public IP to bind to; you need to set the "
"public-ip= and public-port= options"};
}
// create inbound links, if we are a service node
@ -1253,6 +1251,12 @@ namespace llarp
return false;
}
if (not InitOutboundLinks())
{
LogError("failed to init outbound links");
return false;
}
if (IsServiceNode())
{
if (!SaveRC())
@ -1563,6 +1567,22 @@ namespace llarp
return ep and ep->HasExit();
}
std::optional<std::variant<nuint32_t, nuint128_t>>
Router::OurPublicIP() const
{
if (_ourAddress)
return _ourAddress->getIP();
std::optional<std::variant<nuint32_t, nuint128_t>> found;
_linkManager.ForEachInboundLink([&found](const auto& link) {
if (found)
return;
AddressInfo ai;
if (link->GetOurAddressInfo(ai))
found = ai.IP();
});
return found;
}
bool
Router::InitOutboundLinks()
{

@ -102,6 +102,9 @@ namespace llarp
return _dht;
}
std::optional<std::variant<nuint32_t, nuint128_t>>
OurPublicIP() const override;
util::StatusObject
ExtractStatus() const override;

@ -39,11 +39,6 @@ namespace llarp
[](RouterConfig& self) { return self.m_dataDir.c_str(); },
[](RouterConfig& self, std::string dir) { self.m_dataDir = dir; })
.def_readwrite("blockBogons", &RouterConfig::m_blockBogons)
.def(
"overrideAddress",
[](RouterConfig& self, std::string addr) {
self.m_publicAddress = llarp::IpAddress(addr);
})
.def_readwrite("workerThreads", &RouterConfig::m_workerThreads)
.def_readwrite("numNetThreads", &RouterConfig::m_numNetThreads)
.def_readwrite("JobQueueSize", &RouterConfig::m_JobQueueSize);

Loading…
Cancel
Save