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)
|
if(NOT WIN32)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
if (NOT STATIC_LINK)
|
||||||
|
message(FATAL_ERROR "windows requires static builds (thanks balmer)")
|
||||||
|
endif()
|
||||||
|
|
||||||
enable_language(RC)
|
enable_language(RC)
|
||||||
|
|
||||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
option(WITH_WINDOWS_32 "build 32 bit windows" OFF)
|
||||||
|
|
||||||
if(NOT MSVC_VERSION)
|
# unlike unix where you get a *single* compiler ID string in .comment
|
||||||
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-bad-function-cast>)
|
# GNU ld sees fit to merge *all* the .ident sections in object files
|
||||||
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-cast-function-type>)
|
# to .r[o]data section one after the other!
|
||||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
|
add_compile_options(-fno-ident -Wa,-mbig-obj)
|
||||||
# unlike unix where you get a *single* compiler ID string in .comment
|
# the minimum windows version, set to 6 rn because supporting older windows is hell
|
||||||
# GNU ld sees fit to merge *all* the .ident sections in object files
|
set(_winver 0x0600)
|
||||||
# to .r[o]data section one after the other!
|
add_definitions(-D_WIN32_WINNT=${_winver})
|
||||||
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()
|
|
||||||
|
|
||||||
if(EMBEDDED_CFG)
|
if(EMBEDDED_CFG)
|
||||||
link_libatomic()
|
link_libatomic()
|
||||||
endif()
|
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)
|
set(WINDIVERT_VERSION 2.2.0-A CACHE STRING "windivert version")
|
||||||
message("must ship compiler runtime libraries with this build: libwinpthread-1.dll, libgcc_s_dw2-1.dll, and libstdc++-6.dll")
|
set(WINDIVERT_MIRROR https://reqrypt.org/download
|
||||||
message("for release builds, turn on STATIC_LINK in cmake options")
|
CACHE STRING "windivert mirror(s)")
|
||||||
endif()
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "message.hpp"
|
#include "message.hpp"
|
||||||
|
#include "platform.hpp"
|
||||||
|
#include <llarp/config/config.hpp>
|
||||||
#include <llarp/ev/ev.hpp>
|
#include <llarp/ev/ev.hpp>
|
||||||
#include <llarp/net/net.hpp>
|
#include <llarp/net/net.hpp>
|
||||||
#include "unbound_resolver.hpp"
|
#include <llarp/util/fs.hpp>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <unordered_map>
|
namespace llarp::dns
|
||||||
|
|
||||||
namespace llarp
|
|
||||||
{
|
{
|
||||||
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
|
std::weak_ptr<PacketSource_Base> m_Wrapped;
|
||||||
class IQueryHandler
|
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:
|
if (auto ptr = m_Wrapped.lock())
|
||||||
virtual ~IQueryHandler() = default;
|
return ptr->WouldLoop(to, from);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// return true if we should hook this message
|
void
|
||||||
virtual bool
|
SendTo(const SockAddr& to, const SockAddr& from, OwnedBuffer buf) const override
|
||||||
ShouldHookDNSMessage(const Message& msg) const = 0;
|
{
|
||||||
|
m_WritePacket(net::IPPacket::make_udp(from, to, std::move(buf)));
|
||||||
|
}
|
||||||
|
|
||||||
/// handle a hooked message
|
/// stop reading packets and end operation
|
||||||
virtual bool
|
void
|
||||||
HandleHookedDNSMessage(Message query, std::function<void(Message)> sendReply) = 0;
|
Stop() override
|
||||||
};
|
{
|
||||||
|
if (auto ptr = m_Wrapped.lock())
|
||||||
|
ptr->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
// Base class for DNS lookups
|
/// returns the sockaddr we are bound on if applicable
|
||||||
class PacketHandler : public std::enable_shared_from_this<PacketHandler>
|
std::optional<SockAddr>
|
||||||
|
BoundOn() const override
|
||||||
{
|
{
|
||||||
public:
|
if (auto ptr = m_Wrapped.lock())
|
||||||
explicit PacketHandler(EventLoop_ptr loop, IQueryHandler* handler);
|
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
|
void
|
||||||
Start(
|
SendReply(llarp::OwnedBuffer replyBuf) const override
|
||||||
SockAddr localaddr,
|
{
|
||||||
std::vector<SockAddr> upstreamResolvers,
|
src->SendTo(asker, resolver, std::move(replyBuf));
|
||||||
std::vector<fs::path> hostfiles);
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void
|
/// handler of dns query hooking
|
||||||
Stop();
|
/// 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
|
public:
|
||||||
Restart();
|
virtual ~Resolver_Base() = default;
|
||||||
|
|
||||||
void
|
/// less than via rank
|
||||||
HandlePacket(const SockAddr& resolver, const SockAddr& from, llarp_buffer_t buf);
|
bool
|
||||||
|
operator<(const Resolver_Base& other) const
|
||||||
|
{
|
||||||
|
return Rank() < other.Rank();
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
/// greater than via rank
|
||||||
ShouldHandlePacket(const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) const;
|
bool
|
||||||
|
operator>(const Resolver_Base& other) const
|
||||||
|
{
|
||||||
|
return Rank() > other.Rank();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
/// get local socket address that queries are sent from
|
||||||
virtual void
|
virtual std::optional<SockAddr>
|
||||||
SendServerMessageBufferTo(const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) = 0;
|
GetLocalAddr() const
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns true if this packet is something that looks like it's going to an upstream
|
/// get printable name
|
||||||
// resolver, i.e. matches a configured resolver.
|
virtual std::string_view
|
||||||
virtual bool
|
ResolverName() const = 0;
|
||||||
IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const;
|
|
||||||
|
|
||||||
private:
|
/// reset the resolver state, optionally replace upstream info with new info. The default base
|
||||||
void
|
/// implementation does nothing.
|
||||||
HandleUpstreamFailure(const SockAddr& from, const SockAddr& to, Message msg);
|
virtual void
|
||||||
|
ResetResolver(
|
||||||
|
[[maybe_unused]] std::optional<std::vector<SockAddr>> replace_upstream = std::nullopt)
|
||||||
|
{}
|
||||||
|
|
||||||
bool
|
/// cancel all pending requests and cease further operation. Default operation is a no-op.
|
||||||
SetupUnboundResolver(std::vector<SockAddr> resolvers, std::vector<fs::path> hostfiles);
|
virtual void
|
||||||
|
Down()
|
||||||
|
{}
|
||||||
|
|
||||||
IQueryHandler* const m_QueryHandler;
|
/// attempt to handle a dns message
|
||||||
std::set<SockAddr> m_Resolvers;
|
/// returns true if we consumed this query and it should not be processed again
|
||||||
std::shared_ptr<UnboundResolver> m_UnboundResolver;
|
virtual bool
|
||||||
EventLoop_ptr m_Loop;
|
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.
|
/// Returns true if a packet with to and from addresses is something that would cause a
|
||||||
class Proxy : public PacketHandler
|
/// resolution loop and thus should not be used on this resolver
|
||||||
|
virtual bool
|
||||||
|
WouldLoop(const SockAddr& to, const SockAddr& from) const
|
||||||
{
|
{
|
||||||
public:
|
(void)to;
|
||||||
explicit Proxy(EventLoop_ptr loop, IQueryHandler* handler);
|
(void)from;
|
||||||
|
return false;
|
||||||
bool
|
}
|
||||||
Start(
|
};
|
||||||
SockAddr localaddr,
|
|
||||||
std::vector<SockAddr> upstreamResolvers,
|
// Base class for DNS proxy
|
||||||
std::vector<fs::path> hostfiles) override;
|
class Server : public std::enable_shared_from_this<Server>
|
||||||
|
{
|
||||||
protected:
|
protected:
|
||||||
void
|
/// add a packet source to this server, does share ownership
|
||||||
SendServerMessageBufferTo(
|
void
|
||||||
const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) override;
|
AddPacketSource(std::shared_ptr<PacketSource_Base> resolver);
|
||||||
|
/// add a resolver to this packet handler, does share ownership
|
||||||
private:
|
void
|
||||||
std::shared_ptr<UDPHandle> m_Server;
|
AddResolver(std::shared_ptr<Resolver_Base> resolver);
|
||||||
EventLoop_ptr m_Loop;
|
|
||||||
};
|
/// create the platform dependant dns stuff
|
||||||
} // namespace dns
|
virtual std::shared_ptr<I_Platform>
|
||||||
} // namespace llarp
|
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