restucture dbus parts

* move dbus into llarp/linux/dbus.hpp and llarp/linux/dbus.cpp
* provide platform abstraction for setting dns in preparation for network manager
pull/1969/head
Jeff 2 years ago committed by Jeff Becker
parent 2d586145ee
commit 253d22db4f
No known key found for this signature in database
GPG Key ID: 025C02EE3A092F2D

@ -53,10 +53,7 @@ if (ANDROID)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
if(NON_PC_TARGET)
add_import_library(rt)
target_link_libraries(lokinet-platform PUBLIC rt)
endif()
target_sources(lokinet-platform PRIVATE linux/dbus.cpp)
endif()
if (WIN32)

@ -9,6 +9,14 @@ namespace llarp::platform
true
#else
false
#endif
;
/// we have systemd ?
inline constexpr bool has_systemd =
#ifdef WITH_SYSTEMD
true
#else
false
#endif
;

@ -1,92 +1,50 @@
#include "resolver.hpp"
#include <llarp/util/logging.hpp>
#ifndef WITH_SYSTEMD
#include <llarp/constants/platform.hpp>
namespace llarp::dns
{
bool
set_resolver(std::string, llarp::SockAddr, bool)
class Null_SystemSettings : public I_SystemSettings
{
LogDebug("lokinet is not built with systemd support, cannot set systemd resolved DNS");
return false;
}
void
set_resolver(std::string, llarp::SockAddr, bool) override
{
LogDebug("lokinet is not built with systemd support, cannot set systemd resolved DNS");
}
};
} // namespace llarp::dns
#else
#include <stdexcept>
#ifdef WITH_SYSTEMD
extern "C"
{
#include <systemd/sd-bus.h>
#include <net/if.h>
}
#include <llarp/linux/dbus.hpp>
using namespace std::literals;
namespace llarp::dns
{
namespace
class SD_SystemSettings : public I_SystemSettings
{
template <typename... T>
public:
void
resolved_call(sd_bus* bus, const char* method, const char* arg_format, T... args)
{
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message* msg = nullptr;
int r = sd_bus_call_method(
bus,
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager",
method,
&error,
&msg,
arg_format,
args...);
if (r < 0)
throw std::runtime_error{"sdbus resolved "s + method + " failed: " + strerror(-r)};
sd_bus_message_unref(msg);
sd_bus_error_free(&error);
}
struct sd_bus_deleter
set_resolver(std::string ifname, llarp::SockAddr dns, bool global) override
{
void
operator()(sd_bus* ptr) const
unsigned int if_ndx = if_nametoindex(ifname.c_str());
if (if_ndx == 0)
{
sd_bus_unref(ptr);
throw std::runtime_error{"No such interface '" + ifname + "'"};
}
};
} // namespace
bool
set_resolver(std::string ifname, llarp::SockAddr dns, bool global)
{
unsigned int if_ndx = if_nametoindex(ifname.c_str());
if (if_ndx == 0)
{
LogWarn("No such interface '", ifname, "'");
return false;
}
// Connect to the system bus
sd_bus* bus = nullptr;
int r = sd_bus_open_system(&bus);
if (r < 0)
{
LogWarn("Failed to connect to system bus to set DNS: ", strerror(-r));
return false;
}
std::unique_ptr<sd_bus, sd_bus_deleter> bus_ptr{bus};
try
{
// This passing address by bytes and using two separate calls for ipv4/ipv6 is gross, but the
// alternative is to build up a bunch of crap with va_args, which is slightly more gross.
linux::DBUS _dbus{
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
"org.freedesktop.resolve1.Manager"};
// This passing address by bytes and using two separate calls for ipv4/ipv6 is gross, but
// the alternative is to build up a bunch of crap with va_args, which is slightly more
// gross.
const bool isStandardDNSPort = dns.getPort() == 53;
if (dns.isIPv6())
{
@ -95,8 +53,7 @@ namespace llarp::dns
auto* a = reinterpret_cast<const uint8_t*>(&ipv6);
if (isStandardDNSPort)
{
resolved_call(
bus,
_dbus(
"SetLinkDNS",
"ia(iay)",
(int32_t)if_ndx,
@ -111,8 +68,7 @@ namespace llarp::dns
}
else
{
resolved_call(
bus,
_dbus(
"SetLinkDNSEx",
"ia(iayqs)",
(int32_t)if_ndx,
@ -135,8 +91,7 @@ namespace llarp::dns
auto* a = reinterpret_cast<const uint8_t*>(&ipv4);
if (isStandardDNSPort)
{
resolved_call(
bus,
_dbus(
"SetLinkDNS",
"ia(iay)",
(int32_t)if_ndx,
@ -150,8 +105,7 @@ namespace llarp::dns
}
else
{
resolved_call(
bus,
_dbus(
"SetLinkDNSEx",
"ia(iayqs)",
(int32_t)if_ndx,
@ -171,8 +125,7 @@ namespace llarp::dns
// Setting "." as a routing domain gives this DNS server higher priority in resolution
// compared to dns servers that are set without a domain (e.g. the default for a
// DHCP-configured DNS server)
resolved_call(
bus,
_dbus(
"SetLinkDomains",
"ia(sb)",
(int32_t)if_ndx,
@ -180,11 +133,10 @@ namespace llarp::dns
"." // global DNS root
);
else
// Only resolve .loki and .snode through lokinet (so you keep using your local DNS server
// for everything else, which is nicer than forcing everything though lokinet's upstream
// DNS).
resolved_call(
bus,
// Only resolve .loki and .snode through lokinet (so you keep using your local DNS
// server for everything else, which is nicer than forcing everything though lokinet's
// upstream DNS).
_dbus(
"SetLinkDomains",
"ia(sb)",
(int32_t)if_ndx,
@ -194,16 +146,75 @@ namespace llarp::dns
"snode", // domain
(int)1 // routing domain = true
);
return true;
}
catch (const std::exception& e)
};
/// network manager dns setter
class NM_SystemSettings : public I_SystemSettings
{
public:
void
set_resolver(std::string ifname, llarp::SockAddr dns, bool global) override
{
LogWarn("Failed to set DNS via systemd-resolved: ", e.what());
unsigned int if_ndx = if_nametoindex(ifname.c_str());
if (if_ndx == 0)
{
throw std::runtime_error{"No such interface '" + ifname + "'"};
}
(void)dns;
(void)global;
// TODO: implement network manager shit
}
return false;
}
};
} // namespace llarp::dns
#endif // WITH_SYSTEMD
namespace llarp::dns
{
class MultiSettings : public I_SystemSettings
{
std::vector<std::unique_ptr<I_SystemSettings>> m_Impls;
public:
void
add_impl(std::unique_ptr<I_SystemSettings> impl)
{
m_Impls.emplace_back(std::move(impl));
}
void
set_resolver(std::string ifname, llarp::SockAddr dns, bool global) override
{
size_t fails{0};
for (const auto& ptr : m_Impls)
{
try
{
ptr->set_resolver(ifname, dns, global);
}
catch (std::exception& ex)
{
LogWarn(ex.what());
fails++;
}
}
if (fails == m_Impls.size())
throw std::runtime_error{"tried all ways to set resolver and failed"};
}
};
std::shared_ptr<I_SystemSettings>
MakeSystemSettings()
{
auto settings = std::make_shared<MultiSettings>();
settings->add_impl(std::make_unique<Null_SystemSettings>());
if constexpr (llarp::platform::has_systemd)
{
settings->add_impl(std::make_unique<SD_SystemSettings>());
settings->add_impl(std::make_unique<NM_SystemSettings>());
}
return settings;
}
} // namespace llarp::dns

@ -1,21 +1,59 @@
#pragma once
#include <string>
#include <memory>
#include <llarp/net/sock_addr.hpp>
#include <llarp/util/logging.hpp>
#include <stdexcept>
namespace llarp
{
struct AbstractRouter;
}
namespace llarp::dns
{
/// Attempts to set lokinet as the DNS server for systemd-resolved.
/// Returns true if successful, false if unsupported or fails.
///
/// If systemd support is enabled it will attempt via dbus call to system-resolved
/// When compiled without systemd support this always return false without doing anything.
///
/// \param if_name -- the interface name to which we add the DNS servers, e.g. lokitun0.
/// Typically tun_endpoint.GetIfName().
/// \param dns -- the listening address of the lokinet DNS server
/// \param global -- whether to set up lokinet for all DNS queries (true) or just .loki & .snode
/// addresses (false).
bool
set_resolver(std::string if_name, llarp::SockAddr dns, bool global);
/// sets dns settings in a platform dependant way
class I_SystemSettings
{
public:
virtual ~I_SystemSettings() = default;
/// Attempts to set lokinet as the DNS server.
/// throws if unsupported or fails.
///
///
/// \param if_name -- the interface name to which we add the DNS servers, e.g. lokitun0.
/// Typically tun_endpoint.GetIfName().
/// \param dns -- the listening address of the lokinet DNS server
/// \param global -- whether to set up lokinet for all DNS queries (true) or just .loki & .snode
/// addresses (false).
virtual void
set_resolver(std::string if_name, llarp::SockAddr dns, bool global) = 0;
};
/// creates for the current platform
std::shared_ptr<I_SystemSettings>
MakeSystemSettings();
/// compat wrapper
inline bool
set_resolver(std::string if_name, llarp::SockAddr dns, bool global)
{
try
{
if (auto settings = MakeSystemSettings())
{
settings->set_resolver(std::move(if_name), std::move(dns), global);
return true;
}
}
catch (std::exception& ex)
{
LogError("failed to set DNS: ", ex.what());
}
LogWarn("did not set dns");
return false;
}
} // namespace llarp::dns

@ -0,0 +1,26 @@
#ifdef WITH_SYSTEMD
#include "dbus.hpp"
namespace llarp::linux
{
system_bus_exception::system_bus_exception(int err)
: std::runtime_error{"cannot connect to system bus: " + std::string{strerror(-err)}}
{}
dbus_call_exception::dbus_call_exception(std::string meth, int err)
: std::runtime_error{
"failed to call dbus function '" + meth + "': " + std::string{strerror(-err)}}
{}
DBUS::DBUS(std::string _interface, std::string _instance, std::string _call)
: m_interface{std::move(_interface)}
, m_instance{std::move(_instance)}
, m_call{std::move(_call)}
{
sd_bus* bus{nullptr};
if (auto err = sd_bus_open_system(&bus); err < 0)
throw system_bus_exception{err};
m_ptr.reset(bus);
}
} // namespace llarp::linux
#endif

@ -0,0 +1,69 @@
#pragma once
extern "C"
{
#include <systemd/sd-bus.h>
}
#include <memory>
#include <stdexcept>
#include <string>
namespace llarp::linux
{
/// exception for connecting to system bus
class system_bus_exception : public std::runtime_error
{
public:
explicit system_bus_exception(int err);
};
/// exception for a failed calling of a dbus method
class dbus_call_exception : public std::runtime_error
{
public:
explicit dbus_call_exception(std::string meth, int err);
};
class DBUS
{
struct sd_bus_deleter
{
void
operator()(sd_bus* ptr) const
{
sd_bus_unref(ptr);
}
};
std::unique_ptr<sd_bus, sd_bus_deleter> m_ptr;
const std::string m_interface;
const std::string m_instance;
const std::string m_call;
public:
DBUS(std::string _interface, std::string _instance, std::string _call);
template <typename... T>
void
operator()(std::string method, const char* arg_format, T... args)
{
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message* msg = nullptr;
auto r = sd_bus_call_method(
m_ptr.get(),
m_interface.c_str(),
m_instance.c_str(),
m_call.c_str(),
method.c_str(),
&error,
&msg,
arg_format,
args...);
if (r < 0)
throw dbus_call_exception{std::move(method), r};
sd_bus_message_unref(msg);
sd_bus_error_free(&error);
}
};
} // namespace llarp::linux
Loading…
Cancel
Save