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() endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux") if(CMAKE_SYSTEM_NAME MATCHES "Linux")
if(NON_PC_TARGET) target_sources(lokinet-platform PRIVATE linux/dbus.cpp)
add_import_library(rt)
target_link_libraries(lokinet-platform PUBLIC rt)
endif()
endif() endif()
if (WIN32) if (WIN32)

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

@ -1,92 +1,50 @@
#include "resolver.hpp" #include "resolver.hpp"
#include <llarp/util/logging.hpp> #include <llarp/util/logging.hpp>
#include <llarp/constants/platform.hpp>
#ifndef WITH_SYSTEMD
namespace llarp::dns namespace llarp::dns
{ {
bool class Null_SystemSettings : public I_SystemSettings
set_resolver(std::string, llarp::SockAddr, bool)
{ {
LogDebug("lokinet is not built with systemd support, cannot set systemd resolved DNS"); void
return false; set_resolver(std::string, llarp::SockAddr, bool) override
} {
LogDebug("lokinet is not built with systemd support, cannot set systemd resolved DNS");
}
};
} // namespace llarp::dns } // namespace llarp::dns
#else #ifdef WITH_SYSTEMD
#include <stdexcept>
extern "C" extern "C"
{ {
#include <systemd/sd-bus.h>
#include <net/if.h> #include <net/if.h>
} }
#include <llarp/linux/dbus.hpp>
using namespace std::literals; using namespace std::literals;
namespace llarp::dns namespace llarp::dns
{ {
namespace class SD_SystemSettings : public I_SystemSettings
{ {
template <typename... T> public:
void void
resolved_call(sd_bus* bus, const char* method, const char* arg_format, T... args) set_resolver(std::string ifname, llarp::SockAddr dns, bool global) override
{
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
{ {
void unsigned int if_ndx = if_nametoindex(ifname.c_str());
operator()(sd_bus* ptr) const 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 linux::DBUS _dbus{
{ "org.freedesktop.resolve1",
// This passing address by bytes and using two separate calls for ipv4/ipv6 is gross, but the "/org/freedesktop/resolve1",
// alternative is to build up a bunch of crap with va_args, which is slightly more gross. "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; const bool isStandardDNSPort = dns.getPort() == 53;
if (dns.isIPv6()) if (dns.isIPv6())
{ {
@ -95,8 +53,7 @@ namespace llarp::dns
auto* a = reinterpret_cast<const uint8_t*>(&ipv6); auto* a = reinterpret_cast<const uint8_t*>(&ipv6);
if (isStandardDNSPort) if (isStandardDNSPort)
{ {
resolved_call( _dbus(
bus,
"SetLinkDNS", "SetLinkDNS",
"ia(iay)", "ia(iay)",
(int32_t)if_ndx, (int32_t)if_ndx,
@ -111,8 +68,7 @@ namespace llarp::dns
} }
else else
{ {
resolved_call( _dbus(
bus,
"SetLinkDNSEx", "SetLinkDNSEx",
"ia(iayqs)", "ia(iayqs)",
(int32_t)if_ndx, (int32_t)if_ndx,
@ -135,8 +91,7 @@ namespace llarp::dns
auto* a = reinterpret_cast<const uint8_t*>(&ipv4); auto* a = reinterpret_cast<const uint8_t*>(&ipv4);
if (isStandardDNSPort) if (isStandardDNSPort)
{ {
resolved_call( _dbus(
bus,
"SetLinkDNS", "SetLinkDNS",
"ia(iay)", "ia(iay)",
(int32_t)if_ndx, (int32_t)if_ndx,
@ -150,8 +105,7 @@ namespace llarp::dns
} }
else else
{ {
resolved_call( _dbus(
bus,
"SetLinkDNSEx", "SetLinkDNSEx",
"ia(iayqs)", "ia(iayqs)",
(int32_t)if_ndx, (int32_t)if_ndx,
@ -171,8 +125,7 @@ namespace llarp::dns
// Setting "." as a routing domain gives this DNS server higher priority in resolution // 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 // compared to dns servers that are set without a domain (e.g. the default for a
// DHCP-configured DNS server) // DHCP-configured DNS server)
resolved_call( _dbus(
bus,
"SetLinkDomains", "SetLinkDomains",
"ia(sb)", "ia(sb)",
(int32_t)if_ndx, (int32_t)if_ndx,
@ -180,11 +133,10 @@ namespace llarp::dns
"." // global DNS root "." // global DNS root
); );
else else
// Only resolve .loki and .snode through lokinet (so you keep using your local DNS server // Only resolve .loki and .snode through lokinet (so you keep using your local DNS
// for everything else, which is nicer than forcing everything though lokinet's upstream // server for everything else, which is nicer than forcing everything though lokinet's
// DNS). // upstream DNS).
resolved_call( _dbus(
bus,
"SetLinkDomains", "SetLinkDomains",
"ia(sb)", "ia(sb)",
(int32_t)if_ndx, (int32_t)if_ndx,
@ -194,16 +146,75 @@ namespace llarp::dns
"snode", // domain "snode", // domain
(int)1 // routing domain = true (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 } // namespace llarp::dns
#endif // WITH_SYSTEMD #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 #pragma once
#include <string> #include <string>
#include <memory>
#include <llarp/net/sock_addr.hpp> #include <llarp/net/sock_addr.hpp>
#include <llarp/util/logging.hpp>
#include <stdexcept>
namespace llarp
{
struct AbstractRouter;
}
namespace llarp::dns namespace llarp::dns
{ {
/// Attempts to set lokinet as the DNS server for systemd-resolved. /// sets dns settings in a platform dependant way
/// Returns true if successful, false if unsupported or fails. class I_SystemSettings
/// {
/// If systemd support is enabled it will attempt via dbus call to system-resolved public:
/// When compiled without systemd support this always return false without doing anything. virtual ~I_SystemSettings() = default;
///
/// \param if_name -- the interface name to which we add the DNS servers, e.g. lokitun0. /// Attempts to set lokinet as the DNS server.
/// Typically tun_endpoint.GetIfName(). /// throws if unsupported or fails.
/// \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). /// \param if_name -- the interface name to which we add the DNS servers, e.g. lokitun0.
bool /// Typically tun_endpoint.GetIfName().
set_resolver(std::string if_name, llarp::SockAddr dns, bool global); /// \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 } // 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