mirror of https://github.com/oxen-io/lokinet
Merge pull request #1969 from majestrate/wintun-windivert-2022-08-02
use wintun and windivert for windows platform bitspull/1994/head
commit
8b321612da
@ -1,32 +1,52 @@
|
||||
if(NOT WIN32)
|
||||
return()
|
||||
endif()
|
||||
if (NOT STATIC_LINK)
|
||||
message(FATAL_ERROR "windows requires static builds (thanks balmer)")
|
||||
endif()
|
||||
|
||||
enable_language(RC)
|
||||
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
if(NOT MSVC_VERSION)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-bad-function-cast>)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-cast-function-type>)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
|
||||
# unlike unix where you get a *single* compiler ID string in .comment
|
||||
# GNU ld sees fit to merge *all* the .ident sections in object files
|
||||
# to .r[o]data section one after the other!
|
||||
add_compile_options(-fno-ident -Wa,-mbig-obj)
|
||||
link_libraries( -lws2_32 -lshlwapi -ldbghelp -luser32 -liphlpapi -lpsapi -luserenv)
|
||||
# the minimum windows version, set to 6 rn because supporting older windows is hell
|
||||
set(_winver 0x0600)
|
||||
add_definitions(-DWINVER=${_winver} -D_WIN32_WINNT=${_winver})
|
||||
endif()
|
||||
option(WITH_WINDOWS_32 "build 32 bit windows" OFF)
|
||||
|
||||
# unlike unix where you get a *single* compiler ID string in .comment
|
||||
# GNU ld sees fit to merge *all* the .ident sections in object files
|
||||
# to .r[o]data section one after the other!
|
||||
add_compile_options(-fno-ident -Wa,-mbig-obj)
|
||||
# the minimum windows version, set to 6 rn because supporting older windows is hell
|
||||
set(_winver 0x0600)
|
||||
add_definitions(-D_WIN32_WINNT=${_winver})
|
||||
|
||||
if(EMBEDDED_CFG)
|
||||
link_libatomic()
|
||||
endif()
|
||||
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN -DWIN32)
|
||||
set(WINTUN_VERSION 0.14.1 CACHE STRING "wintun version")
|
||||
set(WINTUN_MIRROR https://www.wintun.net/builds
|
||||
CACHE STRING "wintun mirror(s)")
|
||||
set(WINTUN_SOURCE wintun-${WINTUN_VERSION}.zip)
|
||||
set(WINTUN_HASH SHA256=07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51
|
||||
CACHE STRING "wintun source hash")
|
||||
|
||||
if (NOT STATIC_LINK AND NOT MSVC)
|
||||
message("must ship compiler runtime libraries with this build: libwinpthread-1.dll, libgcc_s_dw2-1.dll, and libstdc++-6.dll")
|
||||
message("for release builds, turn on STATIC_LINK in cmake options")
|
||||
endif()
|
||||
set(WINDIVERT_VERSION 2.2.0-A CACHE STRING "windivert version")
|
||||
set(WINDIVERT_MIRROR https://reqrypt.org/download
|
||||
CACHE STRING "windivert mirror(s)")
|
||||
set(WINDIVERT_SOURCE WinDivert-${WINDIVERT_VERSION}.zip)
|
||||
set(WINDIVERT_HASH SHA256=2a7630aac0914746fbc565ac862fa096e3e54233883ac52d17c83107496b7a7f
|
||||
CACHE STRING "windivert source hash")
|
||||
|
||||
set(WINTUN_URL ${WINTUN_MIRROR}/${WINTUN_SOURCE}
|
||||
CACHE STRING "wintun download url")
|
||||
set(WINDIVERT_URL ${WINDIVERT_MIRROR}/${WINDIVERT_SOURCE}
|
||||
CACHE STRING "windivert download url")
|
||||
|
||||
message(STATUS "Downloading wintun from ${WINTUN_URL}")
|
||||
file(DOWNLOAD ${WINTUN_URL} ${CMAKE_BINARY_DIR}/wintun.zip EXPECTED_HASH ${WINTUN_HASH})
|
||||
message(STATUS "Downloading windivert from ${WINDIVERT_URL}")
|
||||
file(DOWNLOAD ${WINDIVERT_URL} ${CMAKE_BINARY_DIR}/windivert.zip EXPECTED_HASH ${WINDIVERT_HASH})
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar x ${CMAKE_BINARY_DIR}/wintun.zip
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar x ${CMAKE_BINARY_DIR}/windivert.zip
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
@ -0,0 +1,2 @@
|
||||
[logging]
|
||||
level=debug
|
@ -0,0 +1,5 @@
|
||||
#
|
||||
# "suggested" default exit node config
|
||||
#
|
||||
[network]
|
||||
exit-node=exit.loki
|
@ -0,0 +1,5 @@
|
||||
#
|
||||
# persist .loki address in a private key file in the data dir
|
||||
#
|
||||
[network]
|
||||
keyfile=lokinet-addr.privkey
|
@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
if ! [ -f LICENSE ] || ! [ -d llarp ]; then
|
||||
echo "You need to run this as ./contrib/mac.sh from the top-level lokinet project directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p build-mac
|
||||
cd build-mac
|
||||
cmake \
|
||||
-G Ninja \
|
||||
-DBUILD_STATIC_DEPS=ON \
|
||||
-DBUILD_LIBLOKINET=OFF \
|
||||
-DWITH_TESTS=OFF \
|
||||
-DWITH_BOOTSTRAP=OFF \
|
||||
-DNATIVE_BUILD=OFF \
|
||||
-DWITH_LTO=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DMACOS_SYSTEM_EXTENSION=ON \
|
||||
-DCODESIGN=ON \
|
||||
-DBUILD_PACKAGE=ON \
|
||||
"$@" \
|
||||
..
|
||||
|
||||
echo "cmake build configured in build-mac"
|
@ -1,17 +0,0 @@
|
||||
#include "table.hpp"
|
||||
#include <llarp/crypto/crypto.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace consensus
|
||||
{
|
||||
ShortHash
|
||||
Table::CalculateHash() const
|
||||
{
|
||||
ShortHash h;
|
||||
const llarp_buffer_t buf(begin()->data(), size());
|
||||
CryptoManager::instance()->shorthash(h, buf);
|
||||
return h;
|
||||
}
|
||||
} // namespace consensus
|
||||
} // namespace llarp
|
@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/crypto/types.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace consensus
|
||||
{
|
||||
/// consensus table
|
||||
struct Table : public std::vector<RouterID>
|
||||
{
|
||||
ShortHash
|
||||
CalculateHash() const;
|
||||
};
|
||||
} // namespace consensus
|
||||
} // namespace llarp
|
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace llarp::constants
|
||||
{
|
||||
constexpr auto udp_header_bytes = 8;
|
||||
constexpr auto ip_header_min_bytes = 20;
|
||||
} // namespace llarp::constants
|
@ -0,0 +1,21 @@
|
||||
#include "nm_platform.hpp"
|
||||
#ifdef WITH_SYSTEMD
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <net/if.h>
|
||||
}
|
||||
|
||||
#include <llarp/linux/dbus.hpp>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace llarp::dns::nm
|
||||
{
|
||||
void
|
||||
Platform::set_resolver(unsigned int, llarp::SockAddr, bool)
|
||||
{
|
||||
// todo: implement me eventually
|
||||
}
|
||||
} // namespace llarp::dns::nm
|
||||
#endif
|
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "platform.hpp"
|
||||
|
||||
#include <llarp/constants/platform.hpp>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llarp::dns
|
||||
{
|
||||
namespace nm
|
||||
{
|
||||
// a dns platform that sets dns via network manager
|
||||
class Platform : public I_Platform
|
||||
{
|
||||
public:
|
||||
virtual ~Platform() = default;
|
||||
|
||||
void
|
||||
set_resolver(unsigned int index, llarp::SockAddr dns, bool global) override;
|
||||
};
|
||||
}; // namespace nm
|
||||
using NM_Platform_t = std::conditional_t<false, nm::Platform, Null_Platform>;
|
||||
} // namespace llarp::dns
|
@ -0,0 +1,32 @@
|
||||
#include "platform.hpp"
|
||||
|
||||
namespace llarp::dns
|
||||
{
|
||||
void
|
||||
Multi_Platform::add_impl(std::unique_ptr<I_Platform> impl)
|
||||
{
|
||||
m_Impls.emplace_back(std::move(impl));
|
||||
}
|
||||
|
||||
void
|
||||
Multi_Platform::set_resolver(unsigned int index, llarp::SockAddr dns, bool global)
|
||||
{
|
||||
if (m_Impls.empty())
|
||||
return;
|
||||
size_t fails{0};
|
||||
for (const auto& ptr : m_Impls)
|
||||
{
|
||||
try
|
||||
{
|
||||
ptr->set_resolver(index, dns, global);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
log::warning(log::Cat("dns"), "{}", ex.what());
|
||||
fails++;
|
||||
}
|
||||
}
|
||||
if (fails == m_Impls.size())
|
||||
throw std::runtime_error{"tried all ways to set resolver and failed"};
|
||||
}
|
||||
} // namespace llarp::dns
|
@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <llarp/net/sock_addr.hpp>
|
||||
#include <llarp/util/logging.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
namespace llarp::dns
|
||||
{
|
||||
/// sets dns settings in a platform dependant way
|
||||
class I_Platform
|
||||
{
|
||||
public:
|
||||
virtual ~I_Platform() = default;
|
||||
|
||||
/// Attempts to set lokinet as the DNS server.
|
||||
/// throws if unsupported or fails.
|
||||
///
|
||||
///
|
||||
/// \param if_index -- the interface index to which we add the DNS servers, this can be gotten
|
||||
/// from the interface name e.g. lokitun0 (Typically tun_endpoint.GetIfName().) and then put
|
||||
/// through if_nametoindex().
|
||||
/// \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(unsigned int if_index, llarp::SockAddr dns, bool global) = 0;
|
||||
};
|
||||
|
||||
/// a dns platform does silently does nothing, successfully
|
||||
class Null_Platform : public I_Platform
|
||||
{
|
||||
public:
|
||||
~Null_Platform() override = default;
|
||||
void
|
||||
set_resolver(unsigned int, llarp::SockAddr, bool) override
|
||||
{}
|
||||
};
|
||||
|
||||
/// a collection of dns platforms that are tried in order when setting dns
|
||||
class Multi_Platform : public I_Platform
|
||||
{
|
||||
std::vector<std::unique_ptr<I_Platform>> m_Impls;
|
||||
|
||||
public:
|
||||
~Multi_Platform() override = default;
|
||||
/// add a platform to be owned
|
||||
void
|
||||
add_impl(std::unique_ptr<I_Platform> impl);
|
||||
|
||||
/// try all owned platforms to set the resolver, throws if none of them work
|
||||
void
|
||||
set_resolver(unsigned int if_index, llarp::SockAddr dns, bool global) override;
|
||||
};
|
||||
} // namespace llarp::dns
|
@ -0,0 +1,128 @@
|
||||
#ifdef WITH_SYSTEMD
|
||||
#include "sd_platform.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <net/if.h>
|
||||
}
|
||||
|
||||
#include <llarp/linux/dbus.hpp>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace llarp::dns::sd
|
||||
{
|
||||
void
|
||||
Platform::set_resolver(unsigned int if_ndx, llarp::SockAddr dns, bool global)
|
||||
{
|
||||
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())
|
||||
{
|
||||
auto ipv6 = dns.getIPv6();
|
||||
static_assert(sizeof(ipv6) == 16);
|
||||
auto* a = reinterpret_cast<const uint8_t*>(&ipv6);
|
||||
if (isStandardDNSPort)
|
||||
{
|
||||
_dbus(
|
||||
"SetLinkDNS",
|
||||
"ia(iay)",
|
||||
(int32_t)if_ndx,
|
||||
(int)1, // number of "iayqs"s we are passing
|
||||
(int32_t)AF_INET6, // network address type
|
||||
(int)16, // network addr byte size
|
||||
// clang-format off
|
||||
a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
|
||||
a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15] // yuck
|
||||
// clang-format on
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbus(
|
||||
"SetLinkDNSEx",
|
||||
"ia(iayqs)",
|
||||
(int32_t)if_ndx,
|
||||
(int)1, // number of "iayqs"s we are passing
|
||||
(int32_t)AF_INET6, // network address type
|
||||
(int)16, // network addr byte size
|
||||
// clang-format off
|
||||
a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
|
||||
a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], // yuck
|
||||
// clang-format on
|
||||
(uint16_t)dns.getPort(),
|
||||
nullptr // dns server name (for TLS SNI which we don't care about)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ipv4 = dns.getIPv4();
|
||||
static_assert(sizeof(ipv4) == 4);
|
||||
auto* a = reinterpret_cast<const uint8_t*>(&ipv4);
|
||||
if (isStandardDNSPort)
|
||||
{
|
||||
_dbus(
|
||||
"SetLinkDNS",
|
||||
"ia(iay)",
|
||||
(int32_t)if_ndx,
|
||||
(int)1, // number of "iayqs"s we are passing
|
||||
(int32_t)AF_INET, // network address type
|
||||
(int)4, // network addr byte size
|
||||
// clang-format off
|
||||
a[0], a[1], a[2], a[3] // yuck
|
||||
// clang-format on
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbus(
|
||||
"SetLinkDNSEx",
|
||||
"ia(iayqs)",
|
||||
(int32_t)if_ndx,
|
||||
(int)1, // number of "iayqs"s we are passing
|
||||
(int32_t)AF_INET, // network address type
|
||||
(int)4, // network addr byte size
|
||||
// clang-format off
|
||||
a[0], a[1], a[2], a[3], // yuck
|
||||
// clang-format on
|
||||
(uint16_t)dns.getPort(),
|
||||
nullptr // dns server name (for TLS SNI which we don't care about)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (global)
|
||||
// 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)
|
||||
_dbus(
|
||||
"SetLinkDomains",
|
||||
"ia(sb)",
|
||||
(int32_t)if_ndx,
|
||||
(int)1, // array size
|
||||
"." // 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).
|
||||
_dbus(
|
||||
"SetLinkDomains",
|
||||
"ia(sb)",
|
||||
(int32_t)if_ndx,
|
||||
(int)2, // array size
|
||||
"loki", // domain
|
||||
(int)1, // routing domain = true
|
||||
"snode", // domain
|
||||
(int)1 // routing domain = true
|
||||
);
|
||||
}
|
||||
} // namespace llarp::dns::sd
|
||||
#endif
|
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "platform.hpp"
|
||||
|
||||
#include <llarp/constants/platform.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llarp::dns
|
||||
{
|
||||
namespace sd
|
||||
{
|
||||
/// a dns platform that sets dns via systemd resolved
|
||||
class Platform : public I_Platform
|
||||
{
|
||||
public:
|
||||
virtual ~Platform() = default;
|
||||
|
||||
void
|
||||
set_resolver(unsigned int if_index, llarp::SockAddr dns, bool global) override;
|
||||
};
|
||||
} // namespace sd
|
||||
using SD_Platform_t =
|
||||
std::conditional_t<llarp::platform::has_systemd, sd::Platform, Null_Platform>;
|
||||
} // namespace llarp::dns
|
@ -1,99 +1,297 @@
|
||||
#pragma once
|
||||
|
||||
#include "message.hpp"
|
||||
#include "platform.hpp"
|
||||
#include <llarp/config/config.hpp>
|
||||
#include <llarp/ev/ev.hpp>
|
||||
#include <llarp/net/net.hpp>
|
||||
#include "unbound_resolver.hpp"
|
||||
#include <llarp/util/fs.hpp>
|
||||
#include <set>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llarp
|
||||
namespace llarp::dns
|
||||
{
|
||||
namespace dns
|
||||
/// a job handling 1 dns query
|
||||
class QueryJob_Base
|
||||
{
|
||||
protected:
|
||||
/// the original dns query
|
||||
Message m_Query;
|
||||
|
||||
public:
|
||||
explicit QueryJob_Base(Message query) : m_Query{std::move(query)}
|
||||
{}
|
||||
|
||||
virtual ~QueryJob_Base() = default;
|
||||
|
||||
Message&
|
||||
Underlying()
|
||||
{
|
||||
return m_Query;
|
||||
}
|
||||
|
||||
const Message&
|
||||
Underlying() const
|
||||
{
|
||||
return m_Query;
|
||||
}
|
||||
|
||||
/// cancel this operation and inform anyone who cares
|
||||
void
|
||||
Cancel() const;
|
||||
|
||||
/// send a raw buffer back to the querier
|
||||
virtual void
|
||||
SendReply(llarp::OwnedBuffer replyBuf) const = 0;
|
||||
};
|
||||
|
||||
class PacketSource_Base
|
||||
{
|
||||
public:
|
||||
virtual ~PacketSource_Base() = default;
|
||||
|
||||
/// return true if traffic with source and dest addresses would cause a
|
||||
/// loop in resolution and thus should not be sent to query handlers
|
||||
virtual bool
|
||||
WouldLoop(const SockAddr& to, const SockAddr& from) const = 0;
|
||||
|
||||
/// send packet with src and dst address containing buf on this packet source
|
||||
virtual void
|
||||
SendTo(const SockAddr& to, const SockAddr& from, OwnedBuffer buf) const = 0;
|
||||
|
||||
/// stop reading packets and end operation
|
||||
virtual void
|
||||
Stop() = 0;
|
||||
|
||||
/// returns the sockaddr we are bound on if applicable
|
||||
virtual std::optional<SockAddr>
|
||||
BoundOn() const = 0;
|
||||
};
|
||||
|
||||
/// a packet source which will override the sendto function of an wrapped packet source to
|
||||
/// construct a raw ip packet as a reply
|
||||
class PacketSource_Wrapper : public PacketSource_Base
|
||||
{
|
||||
/// handler of dns query hooking
|
||||
class IQueryHandler
|
||||
std::weak_ptr<PacketSource_Base> m_Wrapped;
|
||||
std::function<void(net::IPPacket)> m_WritePacket;
|
||||
|
||||
public:
|
||||
explicit PacketSource_Wrapper(
|
||||
std::weak_ptr<PacketSource_Base> wrapped, std::function<void(net::IPPacket)> write_packet)
|
||||
: m_Wrapped{wrapped}, m_WritePacket{write_packet}
|
||||
{}
|
||||
|
||||
bool
|
||||
WouldLoop(const SockAddr& to, const SockAddr& from) const override
|
||||
{
|
||||
public:
|
||||
virtual ~IQueryHandler() = default;
|
||||
if (auto ptr = m_Wrapped.lock())
|
||||
return ptr->WouldLoop(to, from);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// return true if we should hook this message
|
||||
virtual bool
|
||||
ShouldHookDNSMessage(const Message& msg) const = 0;
|
||||
void
|
||||
SendTo(const SockAddr& to, const SockAddr& from, OwnedBuffer buf) const override
|
||||
{
|
||||
m_WritePacket(net::IPPacket::make_udp(from, to, std::move(buf)));
|
||||
}
|
||||
|
||||
/// handle a hooked message
|
||||
virtual bool
|
||||
HandleHookedDNSMessage(Message query, std::function<void(Message)> sendReply) = 0;
|
||||
};
|
||||
/// stop reading packets and end operation
|
||||
void
|
||||
Stop() override
|
||||
{
|
||||
if (auto ptr = m_Wrapped.lock())
|
||||
ptr->Stop();
|
||||
}
|
||||
|
||||
// Base class for DNS lookups
|
||||
class PacketHandler : public std::enable_shared_from_this<PacketHandler>
|
||||
/// returns the sockaddr we are bound on if applicable
|
||||
std::optional<SockAddr>
|
||||
BoundOn() const override
|
||||
{
|
||||
public:
|
||||
explicit PacketHandler(EventLoop_ptr loop, IQueryHandler* handler);
|
||||
if (auto ptr = m_Wrapped.lock())
|
||||
return ptr->BoundOn();
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
virtual ~PacketHandler() = default;
|
||||
/// non complex implementation of QueryJob_Base for use in things that
|
||||
/// only ever called on the mainloop thread
|
||||
class QueryJob : public QueryJob_Base, std::enable_shared_from_this<QueryJob>
|
||||
{
|
||||
std::shared_ptr<PacketSource_Base> src;
|
||||
const SockAddr resolver;
|
||||
const SockAddr asker;
|
||||
|
||||
public:
|
||||
explicit QueryJob(
|
||||
std::shared_ptr<PacketSource_Base> source,
|
||||
const Message& query,
|
||||
const SockAddr& to_,
|
||||
const SockAddr& from_)
|
||||
: QueryJob_Base{query}, src{source}, resolver{to_}, asker{from_}
|
||||
{}
|
||||
|
||||
virtual bool
|
||||
Start(
|
||||
SockAddr localaddr,
|
||||
std::vector<SockAddr> upstreamResolvers,
|
||||
std::vector<fs::path> hostfiles);
|
||||
void
|
||||
SendReply(llarp::OwnedBuffer replyBuf) const override
|
||||
{
|
||||
src->SendTo(asker, resolver, std::move(replyBuf));
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
Stop();
|
||||
/// handler of dns query hooking
|
||||
/// intercepts dns for internal processing
|
||||
class Resolver_Base
|
||||
{
|
||||
protected:
|
||||
/// return the sorting order for this resolver
|
||||
/// lower means it will be tried first
|
||||
virtual int
|
||||
Rank() const = 0;
|
||||
|
||||
void
|
||||
Restart();
|
||||
public:
|
||||
virtual ~Resolver_Base() = default;
|
||||
|
||||
void
|
||||
HandlePacket(const SockAddr& resolver, const SockAddr& from, llarp_buffer_t buf);
|
||||
/// less than via rank
|
||||
bool
|
||||
operator<(const Resolver_Base& other) const
|
||||
{
|
||||
return Rank() < other.Rank();
|
||||
}
|
||||
|
||||
bool
|
||||
ShouldHandlePacket(const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) const;
|
||||
/// greater than via rank
|
||||
bool
|
||||
operator>(const Resolver_Base& other) const
|
||||
{
|
||||
return Rank() > other.Rank();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
SendServerMessageBufferTo(const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) = 0;
|
||||
/// get local socket address that queries are sent from
|
||||
virtual std::optional<SockAddr>
|
||||
GetLocalAddr() const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Returns true if this packet is something that looks like it's going to an upstream
|
||||
// resolver, i.e. matches a configured resolver.
|
||||
virtual bool
|
||||
IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const;
|
||||
/// get printable name
|
||||
virtual std::string_view
|
||||
ResolverName() const = 0;
|
||||
|
||||
private:
|
||||
void
|
||||
HandleUpstreamFailure(const SockAddr& from, const SockAddr& to, Message msg);
|
||||
/// reset the resolver state, optionally replace upstream info with new info. The default base
|
||||
/// implementation does nothing.
|
||||
virtual void
|
||||
ResetResolver(
|
||||
[[maybe_unused]] std::optional<std::vector<SockAddr>> replace_upstream = std::nullopt)
|
||||
{}
|
||||
|
||||
bool
|
||||
SetupUnboundResolver(std::vector<SockAddr> resolvers, std::vector<fs::path> hostfiles);
|
||||
/// cancel all pending requests and cease further operation. Default operation is a no-op.
|
||||
virtual void
|
||||
Down()
|
||||
{}
|
||||
|
||||
IQueryHandler* const m_QueryHandler;
|
||||
std::set<SockAddr> m_Resolvers;
|
||||
std::shared_ptr<UnboundResolver> m_UnboundResolver;
|
||||
EventLoop_ptr m_Loop;
|
||||
};
|
||||
/// attempt to handle a dns message
|
||||
/// returns true if we consumed this query and it should not be processed again
|
||||
virtual bool
|
||||
MaybeHookDNS(
|
||||
std::shared_ptr<PacketSource_Base> source,
|
||||
const Message& query,
|
||||
const SockAddr& to,
|
||||
const SockAddr& from) = 0;
|
||||
|
||||
// Proxying DNS handler that listens on a UDP port for proper DNS requests.
|
||||
class Proxy : public PacketHandler
|
||||
/// Returns true if a packet with to and from addresses is something that would cause a
|
||||
/// resolution loop and thus should not be used on this resolver
|
||||
virtual bool
|
||||
WouldLoop(const SockAddr& to, const SockAddr& from) const
|
||||
{
|
||||
public:
|
||||
explicit Proxy(EventLoop_ptr loop, IQueryHandler* handler);
|
||||
|
||||
bool
|
||||
Start(
|
||||
SockAddr localaddr,
|
||||
std::vector<SockAddr> upstreamResolvers,
|
||||
std::vector<fs::path> hostfiles) override;
|
||||
|
||||
protected:
|
||||
void
|
||||
SendServerMessageBufferTo(
|
||||
const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<UDPHandle> m_Server;
|
||||
EventLoop_ptr m_Loop;
|
||||
};
|
||||
} // namespace dns
|
||||
} // namespace llarp
|
||||
(void)to;
|
||||
(void)from;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Base class for DNS proxy
|
||||
class Server : public std::enable_shared_from_this<Server>
|
||||
{
|
||||
protected:
|
||||
/// add a packet source to this server, does share ownership
|
||||
void
|
||||
AddPacketSource(std::shared_ptr<PacketSource_Base> resolver);
|
||||
/// add a resolver to this packet handler, does share ownership
|
||||
void
|
||||
AddResolver(std::shared_ptr<Resolver_Base> resolver);
|
||||
|
||||
/// create the platform dependant dns stuff
|
||||
virtual std::shared_ptr<I_Platform>
|
||||
CreatePlatform() const;
|
||||
|
||||
public:
|
||||
virtual ~Server() = default;
|
||||
|
||||
explicit Server(EventLoop_ptr loop, llarp::DnsConfig conf, unsigned int netif_index);
|
||||
|
||||
/// returns all sockaddr we have from all of our PacketSources
|
||||
std::vector<SockAddr>
|
||||
BoundPacketSourceAddrs() const;
|
||||
|
||||
/// returns the first sockaddr we have on our packet sources if we have one
|
||||
std::optional<SockAddr>
|
||||
FirstBoundPacketSourceAddr() const;
|
||||
|
||||
/// add a resolver to this packet handler, does not share ownership
|
||||
void
|
||||
AddResolver(std::weak_ptr<Resolver_Base> resolver);
|
||||
|
||||
/// add a packet source to this server, does not share ownership
|
||||
void
|
||||
AddPacketSource(std::weak_ptr<PacketSource_Base> resolver);
|
||||
|
||||
/// create a packet source bound on bindaddr but does not add it
|
||||
virtual std::shared_ptr<PacketSource_Base>
|
||||
MakePacketSourceOn(const SockAddr& bindaddr, const llarp::DnsConfig& conf);
|
||||
|
||||
/// sets up all internal binds and such and begins operation
|
||||
virtual void
|
||||
Start();
|
||||
|
||||
/// stops all operation
|
||||
virtual void
|
||||
Stop();
|
||||
|
||||
/// reset the internal state
|
||||
virtual void
|
||||
Reset();
|
||||
|
||||
/// create the default resolver for out config
|
||||
virtual std::shared_ptr<Resolver_Base>
|
||||
MakeDefaultResolver();
|
||||
|
||||
std::vector<std::weak_ptr<Resolver_Base>>
|
||||
GetAllResolvers() const;
|
||||
|
||||
/// feed a packet buffer from a packet source.
|
||||
/// returns true if we decided to process the packet and consumed it
|
||||
/// returns false if we dont want to process the packet
|
||||
bool
|
||||
MaybeHandlePacket(
|
||||
std::shared_ptr<PacketSource_Base> pktsource,
|
||||
const SockAddr& resolver,
|
||||
const SockAddr& from,
|
||||
llarp::OwnedBuffer buf);
|
||||
/// set which dns mode we are in.
|
||||
/// true for intercepting all queries. false for just .loki and .snode
|
||||
void
|
||||
SetDNSMode(bool all_queries);
|
||||
|
||||
protected:
|
||||
EventLoop_ptr m_Loop;
|
||||
llarp::DnsConfig m_Config;
|
||||
std::shared_ptr<I_Platform> m_Platform;
|
||||
|
||||
private:
|
||||
const unsigned int m_NetIfIndex;
|
||||
std::set<std::shared_ptr<Resolver_Base>, ComparePtr<std::shared_ptr<Resolver_Base>>>
|
||||
m_OwnedResolvers;
|
||||
std::set<std::weak_ptr<Resolver_Base>, CompareWeakPtr<Resolver_Base>> m_Resolvers;
|
||||
|
||||
std::vector<std::weak_ptr<PacketSource_Base>> m_PacketSources;
|
||||
std::vector<std::shared_ptr<PacketSource_Base>> m_OwnedPacketSources;
|
||||
};
|
||||
|
||||
} // namespace llarp::dns
|
||||
|
@ -0,0 +1,51 @@
|
||||
#include "win32_platform.hpp"
|
||||
#include <llarp/net/net.hpp>
|
||||
|
||||
namespace llarp::dns::win32
|
||||
{
|
||||
void
|
||||
Platform::set_resolver(unsigned int index, llarp::SockAddr dns, bool)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
// clear any previous dns settings
|
||||
m_UndoDNS.clear();
|
||||
|
||||
auto interfaces = m_Loop->Net_ptr()->AllNetworkInterfaces();
|
||||
// remove dns
|
||||
{
|
||||
std::vector<llarp::win32::OneShotExec> jobs;
|
||||
for (const auto& ent : interfaces)
|
||||
{
|
||||
if (ent.index == index)
|
||||
continue;
|
||||
jobs.emplace_back(
|
||||
"netsh.exe", fmt::format("interface ipv4 delete dns \"{}\" all", ent.name));
|
||||
jobs.emplace_back(
|
||||
"netsh.exe", fmt::format("interface ipv6 delete dns \"{}\" all", ent.name));
|
||||
}
|
||||
}
|
||||
// add new dns
|
||||
{
|
||||
std::vector<llarp::win32::OneShotExec> jobs;
|
||||
for (const auto& ent : interfaces)
|
||||
{
|
||||
if (ent.index == index)
|
||||
continue;
|
||||
jobs.emplace_back(
|
||||
"netsh.exe",
|
||||
fmt::format("interface ipv4 add dns \"{}\" {} validate=no", ent.name, dns.asIPv4()));
|
||||
jobs.emplace_back(
|
||||
"netsh.exe",
|
||||
fmt::format("interface ipv6 add dns \"{}\" {} validate=no", ent.name, dns.asIPv6()));
|
||||
m_UndoDNS.emplace_back("netsh.exe", fmt::format("", index));
|
||||
}
|
||||
m_UndoDNS.emplace_back("netsh.exe", "winsock reset");
|
||||
}
|
||||
// flush dns
|
||||
llarp::win32::Exec("ipconfig.exe", "/flushdns");
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace llarp::dns::win32
|
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include "platform.hpp"
|
||||
|
||||
namespace llarp::dns
|
||||
{
|
||||
// TODO: implement me
|
||||
using Win32_Platform_t = Null_Platform;
|
||||
} // 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
|
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include "ip_range.hpp"
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
static constexpr std::array bogonRanges_v6 = {
|
||||
// zero
|
||||
IPRange{huint128_t{0}, netmask_ipv6_bits(128)},
|
||||
// loopback
|
||||
IPRange{huint128_t{1}, netmask_ipv6_bits(128)},
|
||||
// yggdrasil
|
||||
IPRange{huint128_t{uint128_t{0x0200'0000'0000'0000UL, 0UL}}, netmask_ipv6_bits(7)},
|
||||
// multicast
|
||||
IPRange{huint128_t{uint128_t{0xff00'0000'0000'0000UL, 0UL}}, netmask_ipv6_bits(8)},
|
||||
// local
|
||||
IPRange{huint128_t{uint128_t{0xfc00'0000'0000'0000UL, 0UL}}, netmask_ipv6_bits(8)},
|
||||
// local
|
||||
IPRange{huint128_t{uint128_t{0xf800'0000'0000'0000UL, 0UL}}, netmask_ipv6_bits(8)}};
|
||||
|
||||
static constexpr std::array bogonRanges_v4 = {
|
||||
IPRange::FromIPv4(0, 0, 0, 0, 8),
|
||||
IPRange::FromIPv4(10, 0, 0, 0, 8),
|
||||
IPRange::FromIPv4(100, 64, 0, 0, 10),
|
||||
IPRange::FromIPv4(127, 0, 0, 0, 8),
|
||||
IPRange::FromIPv4(169, 254, 0, 0, 16),
|
||||
IPRange::FromIPv4(172, 16, 0, 0, 12),
|
||||
IPRange::FromIPv4(192, 0, 0, 0, 24),
|
||||
IPRange::FromIPv4(192, 0, 2, 0, 24),
|
||||
IPRange::FromIPv4(192, 88, 99, 0, 24),
|
||||
IPRange::FromIPv4(192, 168, 0, 0, 16),
|
||||
IPRange::FromIPv4(198, 18, 0, 0, 15),
|
||||
IPRange::FromIPv4(198, 51, 100, 0, 24),
|
||||
IPRange::FromIPv4(203, 0, 113, 0, 24),
|
||||
IPRange::FromIPv4(224, 0, 0, 0, 4),
|
||||
IPRange::FromIPv4(240, 0, 0, 0, 4)};
|
||||
} // namespace llarp
|
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "ip_range.hpp"
|
||||
|
||||
namespace llarp::net
|
||||
{
|
||||
/// info about a network interface lokinet does not own
|
||||
struct InterfaceInfo
|
||||
{
|
||||
/// human readable name of interface
|
||||
std::string name;
|
||||
/// interface's index
|
||||
int index;
|
||||
/// the addresses owned by this interface
|
||||
std::vector<IPRange> addrs;
|
||||
/// a gateway we can use if it exists
|
||||
std::optional<ipaddr_t> gateway;
|
||||
};
|
||||
} // namespace llarp::net
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue