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.", "provided the public-port option must also be specified.",
}, },
[this](std::string arg) { [this](std::string arg) {
if (not arg.empty()) if (arg.empty())
{ return;
llarp::LogInfo("public ip ", arg, " size ", arg.size()); nuint32_t addr{};
if (not addr.FromString(arg))
throw std::invalid_argument{stringify(arg, " is not a valid IPv4 address")};
if (arg.size() > 15) if (IsIPv4Bogon(addr))
throw std::invalid_argument(stringify("Not a valid IPv4 addr: ", arg)); 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) { conf.defineOption<std::string>("router", "public-address", Hidden, [](std::string) {
if (not arg.empty()) throw std::invalid_argument{
{ "[router]:public-address option no longer supported, use [router]:public-ip and "
llarp::LogWarn( "[router]:public-port instead"};
"*** 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<int>( conf.defineOption<int>(
@ -166,8 +157,7 @@ namespace llarp
[this](int arg) { [this](int arg) {
if (arg <= 0 || arg > std::numeric_limits<uint16_t>::max()) if (arg <= 0 || arg > std::numeric_limits<uint16_t>::max())
throw std::invalid_argument("public-port must be >= 0 and <= 65536"); throw std::invalid_argument("public-port must be >= 0 and <= 65536");
m_PublicPort = ToNet(huint16_t{static_cast<uint16_t>(arg)});
m_publicAddress.setPort(arg);
}); });
conf.defineOption<int>( conf.defineOption<int>(

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

@ -8,6 +8,7 @@
#include <utility> #include <utility>
#include <unordered_set> #include <unordered_set>
#include <llarp/router/abstractrouter.hpp> #include <llarp/router/abstractrouter.hpp>
#include <oxenc/variant.h>
static constexpr auto LINK_LAYER_TICK_INTERVAL = 100ms; static constexpr auto LINK_LAYER_TICK_INTERVAL = 100ms;
@ -129,7 +130,7 @@ namespace llarp
} }
bool 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_Router = router;
m_udp = m_Router->loop()->make_udp( m_udp = m_Router->loop()->make_udp(
@ -142,11 +143,42 @@ namespace llarp
if (ifname == "*") 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; return false;
} }
else 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)) if (const auto maybe = GetInterfaceAddr(ifname, af))
{ {
m_ourAddr = *maybe; m_ourAddr = *maybe;
@ -157,10 +189,11 @@ namespace llarp
{ {
m_ourAddr = SockAddr{ifname + ":0"}; 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")); LogError(
throw e; 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); SendTo_LL(const SockAddr& to, const llarp_buffer_t& pkt);
virtual bool 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> virtual std::shared_ptr<ILinkSession>
NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) = 0; 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; 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 bool
AddressInfo::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf) AddressInfo::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
{ {

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

@ -576,29 +576,56 @@ namespace llarp
return addr.asIPv6(); return addr.asIPv6();
} }
bool namespace net
AllInterfaces(int af, SockAddr& result) {
namespace
{
SockAddr
All(int af)
{ {
if (af == AF_INET) if (af == AF_INET)
{ {
sockaddr_in addr; sockaddr_in addr{};
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(0); addr.sin_port = htons(0);
result = SockAddr{addr}; return SockAddr{addr};
return true;
} }
if (af == AF_INET6) sockaddr_in6 addr6{};
{
sockaddr_in6 addr6;
addr6.sin6_family = AF_INET6; addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(0); addr6.sin6_port = htons(0);
addr6.sin6_addr = IN6ADDR_ANY_INIT; addr6.sin6_addr = IN6ADDR_ANY_INIT;
result = SockAddr{addr6}; return SockAddr{addr6};
return true;
} }
return false; } // namespace
std::optional<SockAddr>
AllInterfaces(SockAddr pub)
{
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;
} }
} // namespace net
#if !defined(TESTNET) #if !defined(TESTNET)
static constexpr std::array bogonRanges_v6 = { static constexpr std::array bogonRanges_v6 = {
@ -692,5 +719,20 @@ namespace llarp
return false; return false;
} }
#endif #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 } // namespace llarp

@ -52,6 +52,12 @@ namespace llarp
bool bool
IsIPv4Bogon(const huint32_t& addr); IsIPv4Bogon(const huint32_t& addr);
inline bool
IsIPv4Bogon(const nuint32_t& addr)
{
return IsIPv4Bogon(ToHost(addr));
}
bool bool
IsBogon(const in6_addr& addr); IsBogon(const in6_addr& addr);
@ -61,8 +67,25 @@ namespace llarp
bool bool
IsBogonRange(const in6_addr& host, const in6_addr& mask); IsBogonRange(const in6_addr& host, const in6_addr& mask);
bool /// get a sock addr we can use for all interfaces given our public address
AllInterfaces(int af, SockAddr& addr); 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 /// get first network interface with public address
bool bool
@ -92,4 +115,8 @@ namespace llarp
} }
#endif #endif
/// return true if we have a network interface with this ip
bool
HasInterfaceAddress(std::variant<nuint32_t, nuint128_t> ip);
} // namespace llarp } // namespace llarp

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

@ -12,6 +12,7 @@
#include <string_view> #include <string_view>
#include <string> #include <string>
#include "net_int.hpp" #include "net_int.hpp"
#include <oxenc/variant.h>
namespace llarp namespace llarp
{ {
@ -81,6 +82,14 @@ namespace llarp
std::string std::string
hostString() const; 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 /// 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. /// address with a valid port is still considered empty.
/// ///
@ -133,6 +142,8 @@ namespace llarp
getIPv6() const; getIPv6() const;
nuint32_t nuint32_t
getIPv4() const; getIPv4() const;
std::variant<nuint32_t, nuint128_t>
getIP() const;
/// in host order /// in host order
huint128_t huint128_t

@ -220,6 +220,10 @@ namespace llarp
virtual const byte_t* virtual const byte_t*
pubkey() const = 0; 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 /// connect to N random routers
virtual void virtual void
ConnectToRandomRouters(int N) = 0; ConnectToRandomRouters(int N) = 0;

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

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

@ -39,11 +39,6 @@ namespace llarp
[](RouterConfig& self) { return self.m_dataDir.c_str(); }, [](RouterConfig& self) { return self.m_dataDir.c_str(); },
[](RouterConfig& self, std::string dir) { self.m_dataDir = dir; }) [](RouterConfig& self, std::string dir) { self.m_dataDir = dir; })
.def_readwrite("blockBogons", &RouterConfig::m_blockBogons) .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("workerThreads", &RouterConfig::m_workerThreads)
.def_readwrite("numNetThreads", &RouterConfig::m_numNetThreads) .def_readwrite("numNetThreads", &RouterConfig::m_numNetThreads)
.def_readwrite("JobQueueSize", &RouterConfig::m_JobQueueSize); .def_readwrite("JobQueueSize", &RouterConfig::m_JobQueueSize);

Loading…
Cancel
Save