lokinet/llarp/apple/context_wrapper.cpp
Jason Rhinelander b81f7025c9
Replace logging with oxen-logger
Replaces custom logging system with spdlog-based oxen logging.  This
commit mainly replaces the backend logging with the spdlog-based system,
but doesn't (yet) convert all the existing LogWarn, etc. to use the new
format-based logging.

New logging statements will look like:

    llarp::log::warning(cat, "blah: {}", val);

where `cat` should be set up in each .cpp or cluster of .cpp files, as
described in the oxen-logging README.

As part of spdlog we get fmt, which gives us nice format strings, where
are applied generously in this commit.

Making types printable now requires two steps:
- add a ToString() method
- add this specialization:

      template <>
      constexpr inline bool llarp::IsToStringFormattable<llarp::Whatever> = true;

This will then allow the type to be printed as a "{}" value in a
fmt::format string.  This is applied to all our printable types here,
and all of the `operator<<` are removed.

This commit also:
- replaces various uses of `operator<<` to ToString()
- replaces various uses of std::stringstream with either fmt::format or
  plain std::string
- Rename some to_string and toString() methods to ToString() for
  consistency (and to work with fmt)
- Replace `stringify(...)` and `make_exception` usage with fmt::format
  (and remove stringify/make_exception from util/str.hpp).
2022-07-15 22:17:59 -03:00

198 lines
5.9 KiB
C++

#include <cstdint>
#include <cstring>
#include <cassert>
#include <llarp/net/ip_packet.hpp>
#include <llarp/config/config.hpp>
#include <llarp/util/fs.hpp>
#include <llarp/util/logging/buffer.hpp>
#include <uvw/loop.h>
#include <llarp/util/logging/logger.hpp>
#include <llarp/util/logging/callback_sink.hpp>
#include "vpn_interface.hpp"
#include "context_wrapper.h"
#include "context.hpp"
namespace
{
// The default 127.0.0.1:53 won't work (because we run unprivileged) so remap it to this (unless
// specifically overridden to something else in the config):
const llarp::SockAddr DefaultDNSBind{"127.0.0.1:1153"};
struct instance_data
{
llarp::apple::Context context;
std::thread runner;
packet_writer_callback packet_writer;
start_reading_callback start_reading;
std::weak_ptr<llarp::apple::VPNInterface> iface;
};
} // namespace
const uint16_t dns_trampoline_port = 1053;
void*
llarp_apple_init(llarp_apple_config* appleconf)
{
llarp::log::ReplaceLogger(std::make_shared<llarp::log::CallbackSink_mt>(
[](const char* msg, void* nslog) { reinterpret_cast<ns_logger_callback>(nslog)(msg); },
nullptr,
appleconf->ns_logger));
try
{
auto config_dir = fs::u8path(appleconf->config_dir);
auto config = std::make_shared<llarp::Config>(config_dir);
fs::path config_path = config_dir / "lokinet.ini";
if (!fs::exists(config_path))
llarp::ensureConfig(config_dir, config_path, /*overwrite=*/false, /*asRouter=*/false);
config->Load(config_path);
// If no range is specified then go look for a free one, set that in the config, and then return
// it to the caller via the char* parameters.
auto& range = config->network.m_ifaddr;
if (!range.addr.h)
{
if (auto maybe = llarp::FindFreeRange())
range = *maybe;
else
throw std::runtime_error{"Could not find any free IP range"};
}
auto addr = llarp::net::TruncateV6(range.addr).ToString();
auto mask = llarp::net::TruncateV6(range.netmask_bits).ToString();
if (addr.size() > 15 || mask.size() > 15)
throw std::runtime_error{"Unexpected non-IPv4 tunnel range configured"};
std::strncpy(appleconf->tunnel_ipv4_ip, addr.c_str(), sizeof(appleconf->tunnel_ipv4_ip));
std::strncpy(
appleconf->tunnel_ipv4_netmask, mask.c_str(), sizeof(appleconf->tunnel_ipv4_netmask));
// TODO: in the future we want to do this properly with our pubkey (see issue #1705), but that's
// going to take a bit more work because we currently can't *get* the (usually) ephemeral pubkey
// at this stage of lokinet configuration. So for now we just stick our IPv4 address into it
// until #1705 gets implemented.
llarp::huint128_t ipv6{
llarp::uint128_t{0xfd2e'6c6f'6b69'0000, llarp::net::TruncateV6(range.addr).h}};
std::strncpy(
appleconf->tunnel_ipv6_ip, ipv6.ToString().c_str(), sizeof(appleconf->tunnel_ipv6_ip));
appleconf->tunnel_ipv6_prefix = 48;
appleconf->upstream_dns[0] = '\0';
for (auto& upstream : config->dns.m_upstreamDNS)
{
if (upstream.isIPv4())
{
std::strcpy(appleconf->upstream_dns, upstream.hostString().c_str());
appleconf->upstream_dns_port = upstream.getPort();
break;
}
}
// The default DNS bind setting just isn't something we can use as a non-root network extension
// so remap the default value to a high port unless explicitly set to something else.
if (config->dns.m_bind == llarp::SockAddr{"127.0.0.1:53"})
config->dns.m_bind = DefaultDNSBind;
// If no explicit bootstrap then set the system default one included with the app bundle
if (config->bootstrap.files.empty())
config->bootstrap.files.push_back(fs::u8path(appleconf->default_bootstrap));
auto inst = std::make_unique<instance_data>();
inst->context.Configure(std::move(config));
inst->context.route_callbacks = appleconf->route_callbacks;
inst->packet_writer = appleconf->packet_writer;
inst->start_reading = appleconf->start_reading;
return inst.release();
}
catch (const std::exception& e)
{
llarp::LogError("Failed to initialize lokinet from config: ", e.what());
}
return nullptr;
}
int
llarp_apple_start(void* lokinet, void* callback_context)
{
auto* inst = static_cast<instance_data*>(lokinet);
inst->context.callback_context = callback_context;
inst->context.m_PacketWriter = [inst, callback_context](int af_family, void* data, size_t size) {
inst->packet_writer(af_family, data, size, callback_context);
return true;
};
inst->context.m_OnReadable = [inst, callback_context](llarp::apple::VPNInterface& iface) {
inst->iface = iface.weak_from_this();
inst->start_reading(callback_context);
};
std::promise<void> result;
inst->runner = std::thread{[inst, &result] {
const llarp::RuntimeOptions opts{};
try
{
inst->context.Setup(opts);
}
catch (...)
{
result.set_exception(std::current_exception());
return;
}
result.set_value();
inst->context.Run(opts);
}};
try
{
result.get_future().get();
}
catch (const std::exception& e)
{
llarp::LogError("Failed to initialize lokinet: ", e.what());
return -1;
}
return 0;
}
uv_loop_t*
llarp_apple_get_uv_loop(void* lokinet)
{
auto& inst = *static_cast<instance_data*>(lokinet);
auto uvw = inst.context.loop->MaybeGetUVWLoop();
assert(uvw);
return uvw->raw();
}
int
llarp_apple_incoming(void* lokinet, const void* bytes, size_t size)
{
auto& inst = *static_cast<instance_data*>(lokinet);
auto iface = inst.iface.lock();
if (!iface)
return -2;
llarp_buffer_t buf{static_cast<const uint8_t*>(bytes), size};
if (iface->OfferReadPacket(buf))
return 0;
llarp::LogError("invalid IP packet: ", llarp::buffer_printer(buf));
return -1;
}
void
llarp_apple_shutdown(void* lokinet)
{
auto* inst = static_cast<instance_data*>(lokinet);
inst->context.CloseAsync();
inst->context.Wait();
inst->runner.join();
delete inst;
}