mirror of https://github.com/oxen-io/lokinet
Merge pull request #1930 from majestrate/issue-1929-06-02-2022
redo bind section of config
This commit is contained in:
commit
6ea97ccaf4
|
@ -170,7 +170,7 @@ if(NOT TARGET sodium)
|
|||
endif()
|
||||
|
||||
if(NOT APPLE)
|
||||
add_compile_options(-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -Wall -Wextra -Wno-unknown-pragmas -Wno-unused-function -Wno-deprecated-declarations -Werror=vla)
|
||||
add_compile_options(-Wall -Wextra -Wno-unknown-pragmas -Wno-unused-function -Wno-deprecated-declarations -Werror=vla)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wno-unknown-warning-option)
|
||||
endif()
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
set +x
|
||||
|
||||
default_abis="armeabi-v7a arm64-v8a x86_64"
|
||||
build_abis=${ABIS:-$default_abis}
|
||||
|
||||
test x$NDK = x && echo "NDK env var not set"
|
||||
test x$NDK = x && test -e /usr/lib/android-ndk && export NDK=/usr/lib/android-ndk
|
||||
test x$NDK = x && exit 1
|
||||
|
||||
echo "building abis: $build_abis"
|
||||
|
||||
root="$(readlink -f $(dirname $0)/../)"
|
||||
build=$root/build-android
|
||||
root=$(readlink -f "$1")
|
||||
shift
|
||||
build=$(readlink -f "$1")
|
||||
shift
|
||||
mkdir -p $build
|
||||
cd $build
|
||||
|
||||
|
@ -19,6 +20,7 @@ for abi in $build_abis; do
|
|||
mkdir -p build-$abi
|
||||
cd build-$abi
|
||||
cmake \
|
||||
-S "$root" -B . \
|
||||
-G 'Unix Makefiles' \
|
||||
-DANDROID=ON \
|
||||
-DANDROID_ABI=$abi \
|
||||
|
@ -37,12 +39,13 @@ for abi in $build_abis; do
|
|||
-DWITH_SYSTEMD=OFF \
|
||||
-DFORCE_OXENMQ_SUBMODULE=ON \
|
||||
-DFORCE_OXENC_SUBMODULE=ON \
|
||||
-DFORCE_LOGGING_SUBMODULE=ON \
|
||||
-DFORCE_FMT_SUBMODULE=ON \
|
||||
-DFORCE_SPDLOG_SUBMODULE=ON \
|
||||
-DFORCE_NLOHMANN_SUBMODULE=ON \
|
||||
-DSUBMODULE_CHECK=OFF \
|
||||
-DWITH_LTO=OFF \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
$@ $root
|
||||
$@
|
||||
cd -
|
||||
done
|
||||
rm -f $build/Makefile
|
||||
|
@ -53,4 +56,11 @@ for abi in $build_abis; do
|
|||
echo -ne '$(MAKE) -C ' >> $build/Makefile
|
||||
echo "build-$abi lokinet-android" >> $build/Makefile
|
||||
echo -ne "\tmkdir -p out/$abi && cp build-$abi/jni/liblokinet-android.so out/$abi/liblokinet-android.so\n\n" >> $build/Makefile
|
||||
echo -ne "clean-$abi:\n\t" >> $build/Makefile
|
||||
echo -ne '$(MAKE) -C ' >> $build/Makefile
|
||||
echo "build-$abi clean" >> $build/Makefile
|
||||
done
|
||||
|
||||
echo -ne "clean:" >> $build/Makefile
|
||||
for targ in $build_abis ; do echo -ne " clean-$targ" >> $build/Makefile ; done
|
||||
echo "" >> $build/Makefile
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
set -e
|
||||
set +x
|
||||
|
||||
test x$NDK = x && echo "NDK env var not set"
|
||||
test x$NDK = x && exit 1
|
||||
root="$(readlink -f $(dirname $0)/../)"
|
||||
cd "$root"
|
||||
./contrib/android-configure.sh $@
|
||||
./contrib/android-configure.sh . build-android $@
|
||||
make -C build-android -j ${JOBS:-$(nproc)}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
set -x
|
||||
|
||||
root=$(readlink -f "$1")
|
||||
shift
|
||||
mkdir -p "$1"
|
||||
build=$(readlink -f "$1")
|
||||
shift
|
||||
cd "$build"
|
||||
cmake \
|
||||
-S "$root" -B "$build" \
|
||||
-G 'Unix Makefiles' \
|
||||
-DCMAKE_EXE_LINKER_FLAGS=-fstack-protector \
|
||||
-DCMAKE_CXX_FLAGS=-fdiagnostics-color=always \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$root/contrib/cross/mingw64.cmake" \
|
||||
-DBUILD_STATIC_DEPS=ON \
|
||||
-DBUILD_PACKAGE=ON \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DBUILD_LIBLOKINET=OFF \
|
||||
-DWITH_TESTS=OFF \
|
||||
-DNATIVE_BUILD=OFF \
|
||||
-DSTATIC_LINK=ON \
|
||||
-DWITH_SYSTEMD=OFF \
|
||||
-DFORCE_OXENMQ_SUBMODULE=ON \
|
||||
-DFORCE_OXENC_SUBMODULE=ON \
|
||||
-DFORCE_FMT_SUBMODULE=ON \
|
||||
-DFORCE_SPDLOG_SUBMODULE=ON \
|
||||
-DFORCE_NLOHMANN_SUBMODULE=ON \
|
||||
-DSUBMODULE_CHECK=OFF \
|
||||
-DWITH_LTO=OFF \
|
||||
$@
|
|
@ -6,28 +6,9 @@
|
|||
|
||||
set -e
|
||||
set +x
|
||||
mkdir -p build-windows
|
||||
cd build-windows
|
||||
cmake \
|
||||
-G 'Unix Makefiles' \
|
||||
-DCMAKE_EXE_LINKER_FLAGS=-fstack-protector \
|
||||
-DCMAKE_CXX_FLAGS=-fdiagnostics-color=always\
|
||||
-DCMAKE_TOOLCHAIN_FILE=../contrib/cross/mingw64.cmake\
|
||||
-DBUILD_STATIC_DEPS=ON \
|
||||
-DBUILD_PACKAGE=ON \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DBUILD_LIBLOKINET=OFF \
|
||||
-DWITH_TESTS=OFF \
|
||||
-DNATIVE_BUILD=OFF \
|
||||
-DSTATIC_LINK=ON \
|
||||
-DWITH_SYSTEMD=OFF \
|
||||
-DFORCE_OXENMQ_SUBMODULE=ON \
|
||||
-DFORCE_OXENC_SUBMODULE=ON \
|
||||
-DFORCE_LOGGING_SUBMODULE=ON \
|
||||
-DFORCE_NLOHMANN_SUBMODULE=ON \
|
||||
-DSUBMODULE_CHECK=OFF \
|
||||
-DWITH_LTO=OFF \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
$@ ..
|
||||
make package -j${JOBS:-$(nproc)}
|
||||
|
||||
|
||||
root="$(readlink -f $(dirname $0)/../)"
|
||||
cd "$root"
|
||||
./contrib/windows-configure.sh . build-windows $@
|
||||
make package -j${JOBS:-$(nproc)} -C build-windows
|
||||
|
|
|
@ -100,14 +100,8 @@ namespace llarp
|
|||
virtual std::shared_ptr<llarp::vpn::Platform>
|
||||
makeVPNPlatform();
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
int androidFD = -1;
|
||||
|
||||
int
|
||||
GetUDPSocket();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Config> config = nullptr;
|
||||
|
||||
|
|
|
@ -77,24 +77,24 @@ extern "C"
|
|||
JNIEXPORT void JNICALL
|
||||
Java_network_loki_lokinet_LokinetDaemon_InjectVPNFD(JNIEnv* env, jobject self)
|
||||
{
|
||||
auto ptr = GetImpl<llarp::Context>(env, self);
|
||||
|
||||
ptr->androidFD = GetObjectMemberAsInt<int>(env, self, "m_FD");
|
||||
if (auto ptr = GetImpl<llarp::Context>(env, self))
|
||||
ptr->androidFD = GetObjectMemberAsInt<int>(env, self, "m_FD");
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_network_loki_lokinet_LokinetDaemon_GetUDPSocket(JNIEnv* env, jobject self)
|
||||
{
|
||||
auto ptr = GetImpl<llarp::Context>(env, self);
|
||||
|
||||
return ptr->GetUDPSocket();
|
||||
if (const auto& router = ptr->router; ptr and ptr->router)
|
||||
return router->OutboundUDPSocket();
|
||||
return -1;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_network_loki_lokinet_LokinetDaemon_DetectFreeRange(JNIEnv* env, jclass)
|
||||
{
|
||||
std::string rangestr{};
|
||||
if (auto maybe = llarp::FindFreeRange())
|
||||
if (auto maybe = llarp::net::Platform::Default_ptr()->FindFreeRange())
|
||||
{
|
||||
rangestr = maybe->ToString();
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ llarp_apple_init(llarp_apple_config* appleconf)
|
|||
auto& range = config->network.m_ifaddr;
|
||||
if (!range.addr.h)
|
||||
{
|
||||
if (auto maybe = llarp::FindFreeRange())
|
||||
if (auto maybe = llarp::net::Platform::Default_ptr()->FindFreeRange())
|
||||
range = *maybe;
|
||||
else
|
||||
throw std::runtime_error{"Could not find any free IP range"};
|
||||
|
|
|
@ -35,6 +35,17 @@ namespace llarp
|
|||
constexpr int DefaultPublicPort = 1090;
|
||||
|
||||
using namespace config;
|
||||
namespace
|
||||
{
|
||||
struct ConfigGenParameters_impl : public ConfigGenParameters
|
||||
{
|
||||
const llarp::net::Platform*
|
||||
Net_ptr() const
|
||||
{
|
||||
return llarp::net::Platform::Default_ptr();
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void
|
||||
RouterConfig::defineConfigOptions(ConfigDefinition& conf, const ConfigGenParameters& params)
|
||||
|
@ -140,7 +151,7 @@ namespace llarp
|
|||
throw std::invalid_argument{
|
||||
fmt::format("{} is not a publicly routable ip address", addr)};
|
||||
|
||||
m_PublicIP = addr;
|
||||
PublicIP = addr;
|
||||
});
|
||||
|
||||
conf.defineOption<std::string>("router", "public-address", Hidden, [](std::string) {
|
||||
|
@ -161,7 +172,7 @@ namespace llarp
|
|||
[this](int arg) {
|
||||
if (arg <= 0 || arg > std::numeric_limits<uint16_t>::max())
|
||||
throw std::invalid_argument("public-port must be >= 0 and <= 65536");
|
||||
m_PublicPort = ToNet(huint16_t{static_cast<uint16_t>(arg)});
|
||||
PublicPort = ToNet(huint16_t{static_cast<uint16_t>(arg)});
|
||||
});
|
||||
|
||||
conf.defineOption<int>(
|
||||
|
@ -403,7 +414,7 @@ namespace llarp
|
|||
ReachableDefault,
|
||||
AssignmentAcceptor(m_reachable),
|
||||
Comment{
|
||||
"Determines whether we will publish our snapp's introset to the DHT.",
|
||||
"Determines whether we will pubish our snapp's introset to the DHT.",
|
||||
});
|
||||
|
||||
conf.defineOption<int>(
|
||||
|
@ -838,111 +849,166 @@ namespace llarp
|
|||
});
|
||||
}
|
||||
|
||||
LinksConfig::LinkInfo
|
||||
LinksConfig::LinkInfoFromINIValues(std::string_view name, std::string_view value)
|
||||
{
|
||||
// we treat the INI k:v pair as:
|
||||
// k: interface name, * indicating outbound
|
||||
// v: a comma-separated list of values, an int indicating port (everything else ignored)
|
||||
// this is somewhat of a backwards- and forwards-compatibility thing
|
||||
|
||||
LinkInfo info;
|
||||
info.port = 0;
|
||||
info.addressFamily = AF_INET;
|
||||
|
||||
if (name == "address")
|
||||
{
|
||||
const IpAddress addr{value};
|
||||
if (not addr.hasPort())
|
||||
throw std::invalid_argument("no port provided in link address");
|
||||
info.m_interface = addr.toHost();
|
||||
info.port = *addr.getPort();
|
||||
}
|
||||
else
|
||||
{
|
||||
info.m_interface = std::string{name};
|
||||
|
||||
std::vector<std::string_view> splits = split(value, ",");
|
||||
for (std::string_view str : splits)
|
||||
{
|
||||
int asNum = std::atoi(str.data());
|
||||
if (asNum > 0)
|
||||
info.port = asNum;
|
||||
|
||||
// otherwise, ignore ("future-proofing")
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
LinksConfig::defineConfigOptions(ConfigDefinition& conf, const ConfigGenParameters& params)
|
||||
{
|
||||
constexpr Default DefaultOutboundLinkValue{"0"};
|
||||
|
||||
conf.addSectionComments(
|
||||
"bind",
|
||||
{
|
||||
"This section specifies network interface names and/or IPs as keys, and",
|
||||
"ports as values to control the address(es) on which Lokinet listens for",
|
||||
"incoming data.",
|
||||
"Typically this section can be left blank, but can be used to specify which sockets to "
|
||||
"bind on for inbound and outbound traffic.",
|
||||
"",
|
||||
"If no inbound bind addresses are configured then lokinet will search for a local ",
|
||||
"network interface with a public IP address and use that IP with port 1090.",
|
||||
"If no outbound bind addresses are configured then lokinet will use a wildcard "
|
||||
"address.",
|
||||
"",
|
||||
"Examples:",
|
||||
"",
|
||||
" eth0=1090",
|
||||
" 0.0.0.0=1090",
|
||||
" 1.2.3.4=1090",
|
||||
" inbound=15.5.29.5:443",
|
||||
" inbound=10.0.2.2",
|
||||
" outbound=0.0.0.0:9000",
|
||||
"",
|
||||
"The first bind to port 1090 on the network interface 'eth0'; the second binds",
|
||||
"to port 1090 on all local network interfaces; and the third example binds to",
|
||||
"port 1090 on the given IP address.",
|
||||
"The first binds an inbound socket on local ip 15.5.29.5 with port 443; and the "
|
||||
"second binds an inbound socket on local ip 10.0.2.2 with the default port, 1090; and "
|
||||
"the third example binds an outbound socket on all interfaces with a pinned outbound "
|
||||
"port on port 9000.",
|
||||
"",
|
||||
"If a private range IP address (or an interface with a private IP) is given, or",
|
||||
"if the 0.0.0.0 all-address IP is given then you must also specify the",
|
||||
"public-ip= and public-port= settings in the [router] section with a public",
|
||||
"address at which this router can be reached.",
|
||||
"Inbound sockets with a wildcard address or private range IP address (like the second "
|
||||
"example entry) will require setting the public-ip= and public-port= settings with a "
|
||||
"public address at which this router can be reached.",
|
||||
"Inbound sockets can NOT have ports explicitly set to be 0.",
|
||||
"",
|
||||
"Typically this section can be left blank: if no inbound bind addresses are",
|
||||
"configured then lokinet will search for a local network interface with a public",
|
||||
"IP address and use that (with port 1090).",
|
||||
"On setups with multiple public ip addresses on a network interface, the first ip will "
|
||||
"be used as a default or when a wildcard is provided, unless explicitly set in config.",
|
||||
"Setting the IP for both inbound and outbound sockets on machines with multiple public "
|
||||
"ip addresses is highly recommended.",
|
||||
});
|
||||
|
||||
const auto* net_ptr = params.Net_ptr();
|
||||
|
||||
static constexpr Default DefaultInboundPort{uint16_t{1090}};
|
||||
static constexpr Default DefaultOutboundPort{uint16_t{0}};
|
||||
|
||||
conf.defineOption<std::string>(
|
||||
"bind",
|
||||
"public-ip",
|
||||
RelayOnly,
|
||||
Comment{"set our public ip if it is different than the one we detect or if we are unable "
|
||||
"to detect it"},
|
||||
[this](std::string_view arg) {
|
||||
SockAddr pubaddr{arg};
|
||||
PublicAddress = pubaddr.getIP();
|
||||
});
|
||||
conf.defineOption<uint16_t>(
|
||||
"bind",
|
||||
"public-port",
|
||||
RelayOnly,
|
||||
Comment{"set our public port if it is different than the one we detect or if we are unable "
|
||||
"to detect it"},
|
||||
[this](uint16_t arg) { PublicPort = net::port_t::from_host(arg); });
|
||||
|
||||
auto parse_addr_for_link = [net_ptr](const std::string& arg, net::port_t default_port) {
|
||||
std::optional<SockAddr> addr = std::nullopt;
|
||||
// explicitly provided value
|
||||
if (not arg.empty())
|
||||
{
|
||||
if (arg[0] == ':')
|
||||
{
|
||||
// port only case
|
||||
auto port = net::port_t::from_string(arg.substr(1));
|
||||
addr = net_ptr->WildcardWithPort(port);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = SockAddr{arg};
|
||||
if (net_ptr->IsLoopbackAddress(addr->getIP()))
|
||||
throw std::invalid_argument{fmt::format("{} is a loopback address", arg)};
|
||||
}
|
||||
}
|
||||
if (not addr)
|
||||
{
|
||||
// infer public address
|
||||
if (auto maybe_ifname = net_ptr->GetBestNetIF())
|
||||
addr = net_ptr->GetInterfaceAddr(*maybe_ifname);
|
||||
}
|
||||
|
||||
if (addr)
|
||||
{
|
||||
// set port if not explicitly provided
|
||||
if (addr->getPort() == 0)
|
||||
addr->setPort(default_port);
|
||||
}
|
||||
return addr;
|
||||
};
|
||||
|
||||
conf.defineOption<std::string>(
|
||||
"bind",
|
||||
"inbound",
|
||||
RelayOnly,
|
||||
MultiValue,
|
||||
Comment{""},
|
||||
[this, parse_addr_for_link](const std::string& arg) {
|
||||
auto default_port = net::port_t::from_host(DefaultInboundPort.val);
|
||||
if (auto addr = parse_addr_for_link(arg, default_port))
|
||||
InboundListenAddrs.emplace_back(std::move(*addr));
|
||||
});
|
||||
|
||||
conf.defineOption<std::string>(
|
||||
"bind",
|
||||
"*",
|
||||
DefaultOutboundLinkValue,
|
||||
Comment{
|
||||
"Specify a source port for **outgoing** Lokinet traffic, for example if you want to",
|
||||
"set up custom firewall rules based on the originating port. Typically this should",
|
||||
"be left unset to automatically choose random source ports.",
|
||||
},
|
||||
[this](std::string arg) { m_OutboundLink = LinkInfoFromINIValues("*", arg); });
|
||||
"outbound",
|
||||
MultiValue,
|
||||
Comment{""},
|
||||
[this, net_ptr, parse_addr_for_link](const std::string& arg) {
|
||||
auto default_port = net::port_t::from_host(DefaultOutboundPort.val);
|
||||
auto addr = parse_addr_for_link(arg, default_port);
|
||||
if (not addr)
|
||||
addr = net_ptr->WildcardWithPort(default_port);
|
||||
OutboundLinks.emplace_back(std::move(*addr));
|
||||
});
|
||||
|
||||
if (params.isRelay)
|
||||
{
|
||||
if (std::string best_if; GetBestNetIF(best_if))
|
||||
m_InboundLinks.push_back(LinkInfoFromINIValues(best_if, std::to_string(DefaultPublicPort)));
|
||||
}
|
||||
conf.addUndeclaredHandler(
|
||||
"bind",
|
||||
[&, defaulted = true](
|
||||
std::string_view, std::string_view name, std::string_view value) mutable {
|
||||
if (defaulted)
|
||||
"bind", [this, net_ptr](std::string_view, std::string_view key, std::string_view val) {
|
||||
LogError(
|
||||
"using the [bind] section without inbound= or outbound= is deprecated and will stop "
|
||||
"working in a future release");
|
||||
std::optional<SockAddr> addr;
|
||||
// special case: wildcard for outbound
|
||||
if (key == "*")
|
||||
{
|
||||
m_InboundLinks.clear(); // Clear the default
|
||||
defaulted = false;
|
||||
addr = net_ptr->Wildcard();
|
||||
// set port, zero is acceptable here.
|
||||
if (auto port = std::stoi(std::string{val});
|
||||
port < std::numeric_limits<uint16_t>::max())
|
||||
{
|
||||
addr->setPort(port);
|
||||
}
|
||||
else
|
||||
throw std::invalid_argument{fmt::format("invalid port value: '{}'", val)};
|
||||
OutboundLinks.emplace_back(std::move(*addr));
|
||||
return;
|
||||
}
|
||||
// try as interface name first
|
||||
addr = net_ptr->GetInterfaceAddr(key, AF_INET);
|
||||
if (addr and net_ptr->IsLoopbackAddress(addr->getIP()))
|
||||
throw std::invalid_argument{fmt::format("{} is a loopback interface", key)};
|
||||
// try as ip address next, throws if unable to parse
|
||||
if (not addr)
|
||||
{
|
||||
addr = SockAddr{key, huint16_t{0}};
|
||||
if (net_ptr->IsLoopbackAddress(addr->getIP()))
|
||||
throw std::invalid_argument{fmt::format("{} is a loopback address", key)};
|
||||
}
|
||||
// parse port and set if acceptable non zero value
|
||||
if (auto port = std::stoi(std::string{val});
|
||||
port and port < std::numeric_limits<uint16_t>::max())
|
||||
{
|
||||
addr->setPort(port);
|
||||
}
|
||||
else
|
||||
throw std::invalid_argument{fmt::format("invalid port value: '{}'", val)};
|
||||
|
||||
LinkInfo info = LinkInfoFromINIValues(name, value);
|
||||
|
||||
if (info.port <= 0)
|
||||
throw std::invalid_argument{
|
||||
fmt::format("Invalid [bind] port specified on interface {}", name)};
|
||||
|
||||
assert(name != "*"); // handled by defineOption("bind", "*", ...) above
|
||||
|
||||
m_InboundLinks.emplace_back(std::move(info));
|
||||
InboundListenAddrs.emplace_back(std::move(*addr));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1093,7 +1159,8 @@ namespace llarp
|
|||
constexpr Default DefaultLogType{
|
||||
platform::is_android or platform::is_apple ? "system" : "print"};
|
||||
constexpr Default DefaultLogFile{""};
|
||||
constexpr Default DefaultLogLevel{"warn"};
|
||||
|
||||
const Default DefaultLogLevel{params.isRelay ? "warn" : "info"};
|
||||
|
||||
conf.defineOption<std::string>(
|
||||
"logging",
|
||||
|
@ -1199,8 +1266,14 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
Config::Config(fs::path datadir)
|
||||
: m_DataDir(datadir.empty() ? fs::current_path() : std::move(datadir))
|
||||
std::unique_ptr<ConfigGenParameters>
|
||||
Config::MakeGenParams() const
|
||||
{
|
||||
return std::make_unique<ConfigGenParameters_impl>();
|
||||
}
|
||||
|
||||
Config::Config(std::optional<fs::path> datadir)
|
||||
: m_DataDir{datadir ? std::move(*datadir) : fs::current_path()}
|
||||
{}
|
||||
|
||||
constexpr auto GetOverridesDir = [](auto datadir) -> fs::path { return datadir / "conf.d"; };
|
||||
|
@ -1242,6 +1315,31 @@ namespace llarp
|
|||
m_Additional.emplace_back(std::array<std::string, 3>{section, key, val});
|
||||
}
|
||||
|
||||
bool
|
||||
Config::LoadString(std::string_view ini, bool isRelay)
|
||||
{
|
||||
auto params = MakeGenParams();
|
||||
params->isRelay = isRelay;
|
||||
params->defaultDataDir = m_DataDir;
|
||||
ConfigDefinition conf{isRelay};
|
||||
initializeConfig(conf, *params);
|
||||
|
||||
m_Parser.Clear();
|
||||
if (not m_Parser.LoadFromStr(ini))
|
||||
return false;
|
||||
|
||||
m_Parser.IterAll([&](std::string_view section, const SectionValues_t& values) {
|
||||
for (const auto& pair : values)
|
||||
{
|
||||
conf.addConfigValue(section, pair.first, pair.second);
|
||||
}
|
||||
});
|
||||
|
||||
conf.process();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Config::Load(std::optional<fs::path> fname, bool isRelay)
|
||||
{
|
||||
|
@ -1249,13 +1347,12 @@ namespace llarp
|
|||
return LoadDefault(isRelay);
|
||||
try
|
||||
{
|
||||
ConfigGenParameters params;
|
||||
params.isRelay = isRelay;
|
||||
params.defaultDataDir = m_DataDir;
|
||||
auto params = MakeGenParams();
|
||||
params->isRelay = isRelay;
|
||||
params->defaultDataDir = m_DataDir;
|
||||
|
||||
ConfigDefinition conf{isRelay};
|
||||
initializeConfig(conf, params);
|
||||
addBackwardsCompatibleConfigOptions(conf);
|
||||
initializeConfig(conf, *params);
|
||||
m_Parser.Clear();
|
||||
if (!m_Parser.LoadFile(*fname))
|
||||
{
|
||||
|
@ -1269,9 +1366,7 @@ namespace llarp
|
|||
conf.addConfigValue(section, pair.first, pair.second);
|
||||
}
|
||||
});
|
||||
|
||||
conf.acceptAllOptions();
|
||||
|
||||
conf.process();
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
|
@ -1284,39 +1379,7 @@ namespace llarp
|
|||
bool
|
||||
Config::LoadDefault(bool isRelay)
|
||||
{
|
||||
try
|
||||
{
|
||||
ConfigGenParameters params;
|
||||
params.isRelay = isRelay;
|
||||
params.defaultDataDir = m_DataDir;
|
||||
ConfigDefinition conf{isRelay};
|
||||
initializeConfig(conf, params);
|
||||
|
||||
m_Parser.Clear();
|
||||
LoadOverrides();
|
||||
|
||||
/// load additional config options added
|
||||
for (const auto& [sect, key, val] : m_Additional)
|
||||
{
|
||||
conf.addConfigValue(sect, key, val);
|
||||
}
|
||||
|
||||
m_Parser.IterAll([&](std::string_view section, const SectionValues_t& values) {
|
||||
for (const auto& pair : values)
|
||||
{
|
||||
conf.addConfigValue(section, pair.first, pair.second);
|
||||
}
|
||||
});
|
||||
|
||||
conf.acceptAllOptions();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LogError("Error trying to init default config: ", e.what());
|
||||
return false;
|
||||
}
|
||||
return LoadString("", isRelay);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1439,12 +1502,12 @@ namespace llarp
|
|||
std::string
|
||||
Config::generateBaseClientConfig()
|
||||
{
|
||||
ConfigGenParameters params;
|
||||
params.isRelay = false;
|
||||
params.defaultDataDir = m_DataDir;
|
||||
auto params = MakeGenParams();
|
||||
params->isRelay = false;
|
||||
params->defaultDataDir = m_DataDir;
|
||||
|
||||
llarp::ConfigDefinition def{false};
|
||||
initializeConfig(def, params);
|
||||
initializeConfig(def, *params);
|
||||
generateCommonConfigComments(def);
|
||||
def.addSectionComments(
|
||||
"paths",
|
||||
|
@ -1464,12 +1527,12 @@ namespace llarp
|
|||
std::string
|
||||
Config::generateBaseRouterConfig()
|
||||
{
|
||||
ConfigGenParameters params;
|
||||
params.isRelay = true;
|
||||
params.defaultDataDir = m_DataDir;
|
||||
auto params = MakeGenParams();
|
||||
params->isRelay = true;
|
||||
params->defaultDataDir = m_DataDir;
|
||||
|
||||
llarp::ConfigDefinition def{true};
|
||||
initializeConfig(def, params);
|
||||
initializeConfig(def, *params);
|
||||
generateCommonConfigComments(def);
|
||||
|
||||
// lokid
|
||||
|
@ -1485,7 +1548,7 @@ namespace llarp
|
|||
std::shared_ptr<Config>
|
||||
Config::EmbeddedConfig()
|
||||
{
|
||||
auto config = std::make_shared<Config>(fs::path{});
|
||||
auto config = std::make_shared<Config>();
|
||||
config->Load();
|
||||
config->logging.m_logLevel = log::Level::off;
|
||||
config->api.m_enableRPCServer = false;
|
||||
|
|
|
@ -39,8 +39,18 @@ namespace llarp
|
|||
/// parameters that need to be passed around.
|
||||
struct ConfigGenParameters
|
||||
{
|
||||
ConfigGenParameters() = default;
|
||||
virtual ~ConfigGenParameters() = default;
|
||||
|
||||
ConfigGenParameters(const ConfigGenParameters&) = delete;
|
||||
ConfigGenParameters(ConfigGenParameters&&) = delete;
|
||||
|
||||
bool isRelay = false;
|
||||
fs::path defaultDataDir;
|
||||
|
||||
/// get network platform (virtual for unit test mocks)
|
||||
virtual const llarp::net::Platform*
|
||||
Net_ptr() const = 0;
|
||||
};
|
||||
|
||||
struct RouterConfig
|
||||
|
@ -55,9 +65,6 @@ namespace llarp
|
|||
|
||||
bool m_blockBogons = false;
|
||||
|
||||
std::optional<nuint32_t> m_PublicIP;
|
||||
nuint16_t m_PublicPort;
|
||||
|
||||
int m_workerThreads = -1;
|
||||
int m_numNetThreads = -1;
|
||||
|
||||
|
@ -69,6 +76,10 @@ namespace llarp
|
|||
std::string m_transportKeyFile;
|
||||
|
||||
bool m_isRelay = false;
|
||||
/// deprecated
|
||||
std::optional<net::ipaddr_t> PublicIP;
|
||||
/// deprecated
|
||||
std::optional<net::port_t> PublicPort;
|
||||
|
||||
void
|
||||
defineConfigOptions(ConfigDefinition& conf, const ConfigGenParameters& params);
|
||||
|
@ -154,19 +165,10 @@ namespace llarp
|
|||
|
||||
struct LinksConfig
|
||||
{
|
||||
struct LinkInfo
|
||||
{
|
||||
std::string m_interface;
|
||||
int addressFamily = -1;
|
||||
uint16_t port = -1;
|
||||
};
|
||||
/// Create a LinkInfo from the given string.
|
||||
/// @throws if str does not represent a LinkInfo.
|
||||
LinkInfo
|
||||
LinkInfoFromINIValues(std::string_view name, std::string_view value);
|
||||
|
||||
LinkInfo m_OutboundLink;
|
||||
std::vector<LinkInfo> m_InboundLinks;
|
||||
std::optional<net::ipaddr_t> PublicAddress;
|
||||
std::optional<net::port_t> PublicPort;
|
||||
std::vector<SockAddr> OutboundLinks;
|
||||
std::vector<SockAddr> InboundListenAddrs;
|
||||
|
||||
void
|
||||
defineConfigOptions(ConfigDefinition& conf, const ConfigGenParameters& params);
|
||||
|
@ -220,9 +222,13 @@ namespace llarp
|
|||
|
||||
struct Config
|
||||
{
|
||||
explicit Config(fs::path datadir);
|
||||
explicit Config(std::optional<fs::path> datadir = std::nullopt);
|
||||
|
||||
~Config() = default;
|
||||
virtual ~Config() = default;
|
||||
|
||||
/// create generation params (virtual for unit test mock)
|
||||
virtual std::unique_ptr<ConfigGenParameters>
|
||||
MakeGenParams() const;
|
||||
|
||||
RouterConfig router;
|
||||
NetworkConfig network;
|
||||
|
@ -250,6 +256,10 @@ namespace llarp
|
|||
bool
|
||||
Load(std::optional<fs::path> fname = std::nullopt, bool isRelay = false);
|
||||
|
||||
// Load a config from a string of ini, same effects as Config::Load
|
||||
bool
|
||||
LoadString(std::string_view ini, bool isRelay = false);
|
||||
|
||||
std::string
|
||||
generateBaseClientConfig();
|
||||
|
||||
|
|
|
@ -89,18 +89,18 @@ namespace llarp
|
|||
// fall back to undeclared handler if needed
|
||||
auto& sectionDefinitions = secItr->second;
|
||||
auto defItr = sectionDefinitions.find(std::string(name));
|
||||
if (defItr == sectionDefinitions.end())
|
||||
if (defItr != sectionDefinitions.end())
|
||||
{
|
||||
if (not haveUndeclaredHandler)
|
||||
throw std::invalid_argument{fmt::format("unrecognized option [{}]:{}", section, name)};
|
||||
auto& handler = undItr->second;
|
||||
handler(section, name, value);
|
||||
OptionDefinition_ptr& definition = defItr->second;
|
||||
definition->parseValue(std::string(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
OptionDefinition_ptr& definition = defItr->second;
|
||||
definition->parseValue(std::string(value));
|
||||
if (not haveUndeclaredHandler)
|
||||
throw std::invalid_argument{fmt::format("unrecognized option [{}]: {}", section, name)};
|
||||
|
||||
auto& handler = undItr->second;
|
||||
handler(section, name, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -142,9 +142,9 @@ namespace llarp
|
|||
void
|
||||
ConfigDefinition::acceptAllOptions()
|
||||
{
|
||||
visitSections([&](const std::string& section, const DefinitionMap&) {
|
||||
visitSections([this](const std::string& section, const DefinitionMap&) {
|
||||
visitDefinitions(
|
||||
section, [&](const std::string&, const OptionDefinition_ptr& def) { def->tryAccept(); });
|
||||
section, [](const std::string&, const OptionDefinition_ptr& def) { def->tryAccept(); });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -243,12 +243,9 @@ namespace llarp
|
|||
std::optional<T>
|
||||
getValue() const
|
||||
{
|
||||
if (parsedValues.size())
|
||||
return parsedValues[0];
|
||||
else if (not required and not multiValued)
|
||||
return defaultValue;
|
||||
else
|
||||
return std::nullopt;
|
||||
if (parsedValues.empty())
|
||||
return required ? std::nullopt : defaultValue;
|
||||
return parsedValues.front();
|
||||
}
|
||||
|
||||
/// Returns the value at the given index.
|
||||
|
@ -340,7 +337,7 @@ namespace llarp
|
|||
void
|
||||
tryAccept() const override
|
||||
{
|
||||
if (required and parsedValues.size() == 0)
|
||||
if (required and parsedValues.empty())
|
||||
{
|
||||
throw std::runtime_error{fmt::format(
|
||||
"cannot call tryAccept() on [{}]:{} when required but no value available",
|
||||
|
@ -348,14 +345,14 @@ namespace llarp
|
|||
name)};
|
||||
}
|
||||
|
||||
// don't use default value if we are multi-valued and have no value
|
||||
if (multiValued and parsedValues.size() == 0)
|
||||
return;
|
||||
|
||||
if (acceptor)
|
||||
{
|
||||
if (multiValued)
|
||||
{
|
||||
// add default value in multi value mode
|
||||
if (defaultValue and parsedValues.empty())
|
||||
acceptor(*defaultValue);
|
||||
|
||||
for (auto value : parsedValues)
|
||||
{
|
||||
acceptor(value);
|
||||
|
@ -365,13 +362,7 @@ namespace llarp
|
|||
{
|
||||
auto maybe = getValue();
|
||||
if (maybe)
|
||||
{
|
||||
acceptor(*maybe);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(not defaultValue); // maybe should have a value if defaultValue does
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -510,6 +501,14 @@ namespace llarp
|
|||
void
|
||||
acceptAllOptions();
|
||||
|
||||
/// validates and accept all parsed options
|
||||
inline void
|
||||
process()
|
||||
{
|
||||
validateRequiredFields();
|
||||
acceptAllOptions();
|
||||
}
|
||||
|
||||
/// Add comments for a given section. Comments are replayed in-order during config file
|
||||
/// generation. A proper comment prefix will automatically be applied, and the entire comment
|
||||
/// will otherwise be used verbatim (no automatic line separation, etc.).
|
||||
|
|
|
@ -8,3 +8,8 @@ constexpr size_t MAX_LINK_MSG_SIZE = 8192;
|
|||
static constexpr auto DefaultLinkSessionLifetime = 5min;
|
||||
constexpr size_t MaxSendQueueSize = 1024 * 16;
|
||||
static constexpr auto LinkLayerConnectTimeout = 5s;
|
||||
|
||||
namespace llarp::constants
|
||||
{
|
||||
static constexpr auto DefaultInboundIWPPort = uint16_t{1090};
|
||||
}
|
||||
|
|
|
@ -211,12 +211,4 @@ namespace llarp
|
|||
loop.reset();
|
||||
}
|
||||
|
||||
#if defined(ANDROID)
|
||||
int
|
||||
Context::GetUDPSocket()
|
||||
{
|
||||
return router->GetOutboundUDPSocket();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace llarp
|
||||
|
|
|
@ -18,14 +18,14 @@ namespace llarp::uv
|
|||
class UVWakeup;
|
||||
class UVRepeater;
|
||||
|
||||
class Loop final : public llarp::EventLoop
|
||||
class Loop : public llarp::EventLoop
|
||||
{
|
||||
public:
|
||||
using Callback = std::function<void()>;
|
||||
|
||||
Loop(size_t queue_size);
|
||||
|
||||
void
|
||||
virtual void
|
||||
run() override;
|
||||
|
||||
bool
|
||||
|
@ -63,7 +63,7 @@ namespace llarp::uv
|
|||
std::shared_ptr<EventLoopRepeater>
|
||||
make_repeater() override;
|
||||
|
||||
std::shared_ptr<llarp::UDPHandle>
|
||||
virtual std::shared_ptr<llarp::UDPHandle>
|
||||
make_udp(UDPReceiveFunc on_recv) override;
|
||||
|
||||
void
|
||||
|
@ -75,8 +75,11 @@ namespace llarp::uv
|
|||
bool
|
||||
inEventLoop() const override;
|
||||
|
||||
private:
|
||||
protected:
|
||||
std::shared_ptr<uvw::Loop> m_Impl;
|
||||
std::optional<std::thread::id> m_EventLoopThreadID;
|
||||
|
||||
private:
|
||||
std::shared_ptr<uvw::AsyncHandle> m_WakeUp;
|
||||
std::atomic<bool> m_Run;
|
||||
using AtomicQueue_t = llarp::thread::Queue<std::function<void(void)>>;
|
||||
|
@ -92,8 +95,6 @@ namespace llarp::uv
|
|||
|
||||
std::unordered_map<int, std::shared_ptr<uvw::PollHandle>> m_Polls;
|
||||
|
||||
std::optional<std::thread::id> m_EventLoopThreadID;
|
||||
|
||||
void
|
||||
wakeup() override;
|
||||
};
|
||||
|
|
|
@ -76,6 +76,15 @@ namespace llarp::vpn
|
|||
IRouteManager(IRouteManager&&) = delete;
|
||||
virtual ~IRouteManager() = default;
|
||||
|
||||
virtual const llarp::net::Platform*
|
||||
Net_ptr() const;
|
||||
|
||||
inline const llarp::net::Platform&
|
||||
Net() const
|
||||
{
|
||||
return *Net_ptr();
|
||||
}
|
||||
|
||||
virtual void
|
||||
AddRoute(IPVariant_t ip, IPVariant_t gateway) = 0;
|
||||
|
||||
|
|
|
@ -710,7 +710,7 @@ namespace llarp
|
|||
m_OurRange = networkConfig.m_ifaddr;
|
||||
if (!m_OurRange.addr.h)
|
||||
{
|
||||
const auto maybe = llarp::FindFreeRange();
|
||||
const auto maybe = m_Router->Net().FindFreeRange();
|
||||
if (not maybe.has_value())
|
||||
throw std::runtime_error("cannot find free interface range");
|
||||
m_OurRange = *maybe;
|
||||
|
@ -725,7 +725,7 @@ namespace llarp
|
|||
m_ifname = networkConfig.m_ifname;
|
||||
if (m_ifname.empty())
|
||||
{
|
||||
const auto maybe = llarp::FindFreeTun();
|
||||
const auto maybe = m_Router->Net().FindFreeTun();
|
||||
if (not maybe.has_value())
|
||||
throw std::runtime_error("cannot find free interface name");
|
||||
m_ifname = *maybe;
|
||||
|
|
|
@ -222,7 +222,7 @@ namespace llarp
|
|||
m_IfName = conf.m_ifname;
|
||||
if (m_IfName.empty())
|
||||
{
|
||||
const auto maybe = llarp::FindFreeTun();
|
||||
const auto maybe = m_router->Net().FindFreeTun();
|
||||
if (not maybe.has_value())
|
||||
throw std::runtime_error("cannot find free interface name");
|
||||
m_IfName = *maybe;
|
||||
|
@ -231,7 +231,7 @@ namespace llarp
|
|||
m_OurRange = conf.m_ifaddr;
|
||||
if (!m_OurRange.addr.h)
|
||||
{
|
||||
const auto maybe = llarp::FindFreeRange();
|
||||
const auto maybe = m_router->Net().FindFreeRange();
|
||||
if (not maybe.has_value())
|
||||
{
|
||||
throw std::runtime_error("cannot find free address range");
|
||||
|
@ -938,7 +938,7 @@ namespace llarp
|
|||
m_OurIPv6 = llarp::huint128_t{
|
||||
llarp::uint128_t{0xfd2e'6c6f'6b69'0000, llarp::net::TruncateV6(m_OurRange.addr).h}};
|
||||
#else
|
||||
const auto maybe = GetInterfaceIPv6Address(m_IfName);
|
||||
const auto maybe = m_router->Net().GetInterfaceIPv6Address(m_IfName);
|
||||
if (maybe.has_value())
|
||||
{
|
||||
m_OurIPv6 = *maybe;
|
||||
|
|
|
@ -129,9 +129,12 @@ namespace llarp
|
|||
visit(s.get());
|
||||
}
|
||||
|
||||
bool
|
||||
ILinkLayer::Configure(AbstractRouter* router, std::string ifname, int af, uint16_t port)
|
||||
void
|
||||
ILinkLayer::Bind(AbstractRouter* router, SockAddr bind_addr)
|
||||
{
|
||||
if (router->Net().IsLoopbackAddress(bind_addr.getIP()))
|
||||
throw std::runtime_error{"cannot udp bind socket on loopback"};
|
||||
m_ourAddr = bind_addr;
|
||||
m_Router = router;
|
||||
m_udp = m_Router->loop()->make_udp(
|
||||
[this]([[maybe_unused]] UDPHandle& udp, const SockAddr& from, llarp_buffer_t buf) {
|
||||
|
@ -141,71 +144,11 @@ namespace llarp
|
|||
RecvFrom(from, std::move(pkt));
|
||||
});
|
||||
|
||||
if (ifname == "*")
|
||||
{
|
||||
if (router->IsServiceNode())
|
||||
{
|
||||
if (auto maybe = router->OurPublicIP())
|
||||
{
|
||||
auto addr = var::visit([](auto&& addr) { return SockAddr{addr}; }, *maybe);
|
||||
// service node outbound link
|
||||
if (HasInterfaceAddress(addr.getIP()))
|
||||
{
|
||||
// we have our ip claimed on a local net interface
|
||||
m_ourAddr = addr;
|
||||
}
|
||||
else if (auto maybe = net::AllInterfaces(addr))
|
||||
{
|
||||
// we do not have our claimed ip, nat or something?
|
||||
m_ourAddr = *maybe;
|
||||
}
|
||||
else if (auto maybe = net::AllInterfaces(SockAddr{"0.0.0.0"}))
|
||||
{
|
||||
// one last fallback
|
||||
m_ourAddr = *maybe;
|
||||
}
|
||||
else
|
||||
return false; // the ultimate failure case
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (auto maybe = net::AllInterfaces(SockAddr{"0.0.0.0"}))
|
||||
{
|
||||
// client outbound link
|
||||
m_ourAddr = *maybe;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ifname == "0.0.0.0" and not GetBestNetIF(ifname))
|
||||
throw std::invalid_argument{
|
||||
"0.0.0.0 provided and we cannot find a valid ip to use, please set one "
|
||||
"explicitly instead in the bind section instead of 0.0.0.0"};
|
||||
if (const auto maybe = GetInterfaceAddr(ifname, af))
|
||||
{
|
||||
m_ourAddr = *maybe;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
m_ourAddr = SockAddr{ifname + ":0"};
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
LogError("Could not use ifname ", ifname, " to configure ILinkLayer: ", ex.what());
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_ourAddr.setPort(port);
|
||||
if (not m_udp->listen(m_ourAddr))
|
||||
return false;
|
||||
if (m_udp->listen(m_ourAddr))
|
||||
return;
|
||||
|
||||
return true;
|
||||
throw std::runtime_error{
|
||||
fmt::format("failed to listen {} udp socket on {}", Name(), m_ourAddr)};
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -107,8 +107,8 @@ namespace llarp
|
|||
void
|
||||
SendTo_LL(const SockAddr& to, const llarp_buffer_t& pkt);
|
||||
|
||||
virtual bool
|
||||
Configure(AbstractRouter* loop, std::string ifname, int af, uint16_t port);
|
||||
void
|
||||
Bind(AbstractRouter* router, SockAddr addr);
|
||||
|
||||
virtual std::shared_ptr<ILinkSession>
|
||||
NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) = 0;
|
||||
|
@ -233,6 +233,13 @@ namespace llarp
|
|||
return m_Router;
|
||||
}
|
||||
|
||||
/// Get the local sock addr we are bound on
|
||||
const SockAddr&
|
||||
LocalSocketAddr() const
|
||||
{
|
||||
return m_ourAddr;
|
||||
}
|
||||
|
||||
private:
|
||||
const SecretKey& m_RouterEncSecret;
|
||||
|
||||
|
|
|
@ -31,6 +31,13 @@ namespace llarp
|
|||
return IPRange{net::ExpandV4(ipaddr_ipv4_bits(a, b, c, d)), netmask_ipv6_bits(mask + 96)};
|
||||
}
|
||||
|
||||
static inline IPRange
|
||||
FromIPv4(net::ipv4addr_t addr, net::ipv4addr_t netmask)
|
||||
{
|
||||
return IPRange{
|
||||
net::ExpandV4(ToHost(addr)), netmask_ipv6_bits(bits::count_bits(netmask) + 96)};
|
||||
}
|
||||
|
||||
/// return true if this iprange is in the IPv4 mapping range for containing ipv4 addresses
|
||||
constexpr bool
|
||||
IsV4() const
|
||||
|
@ -39,6 +46,15 @@ namespace llarp
|
|||
return ipv4_map.Contains(addr);
|
||||
}
|
||||
|
||||
/// get address family
|
||||
constexpr int
|
||||
Family() const
|
||||
{
|
||||
if (IsV4())
|
||||
return AF_INET;
|
||||
return AF_INET6;
|
||||
}
|
||||
|
||||
/// return true if we intersect with a bogon range
|
||||
bool
|
||||
BogonRange() const
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "net_if.hpp"
|
||||
#include <stdexcept>
|
||||
#include <llarp/constants/platform.hpp>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <llarp/android/ifaddrs.h>
|
||||
|
@ -22,13 +23,17 @@
|
|||
#ifdef ANDROID
|
||||
#include <llarp/android/ifaddrs.h>
|
||||
#else
|
||||
#ifndef _WIN32
|
||||
#ifdef _WIN32
|
||||
#include <iphlpapi.h>
|
||||
#include <llarp/win32/exception.hpp>
|
||||
#else
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <list>
|
||||
#include <type_traits>
|
||||
|
||||
bool
|
||||
operator==(const sockaddr& a, const sockaddr& b)
|
||||
|
@ -76,559 +81,408 @@ operator==(const sockaddr_in6& a, const sockaddr_in6& b)
|
|||
return a.sin6_port == b.sin6_port && a.sin6_addr == b.sin6_addr;
|
||||
}
|
||||
|
||||
namespace llarp::net
|
||||
{
|
||||
class Platform_Base : public llarp::net::Platform
|
||||
{
|
||||
public:
|
||||
bool
|
||||
IsLoopbackAddress(ipaddr_t ip) const override
|
||||
{
|
||||
return var::visit(
|
||||
[loopback6 = IPRange{huint128_t{uint128_t{0UL, 1UL}}, netmask_ipv6_bits(128)},
|
||||
loopback4 = IPRange::FromIPv4(127, 0, 0, 0, 8)](auto&& ip) {
|
||||
const auto h_ip = ToHost(ip);
|
||||
return loopback4.Contains(h_ip) or loopback6.Contains(h_ip);
|
||||
},
|
||||
ip);
|
||||
}
|
||||
|
||||
SockAddr
|
||||
Wildcard(int af) const override
|
||||
{
|
||||
if (af == AF_INET)
|
||||
{
|
||||
sockaddr_in addr{};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(0);
|
||||
return SockAddr{addr};
|
||||
}
|
||||
if (af == AF_INET6)
|
||||
{
|
||||
sockaddr_in6 addr6{};
|
||||
addr6.sin6_family = AF_INET6;
|
||||
addr6.sin6_port = htons(0);
|
||||
addr6.sin6_addr = IN6ADDR_ANY_INIT;
|
||||
return SockAddr{addr6};
|
||||
}
|
||||
throw std::invalid_argument{fmt::format("{} is not a valid address family")};
|
||||
}
|
||||
|
||||
bool
|
||||
IsBogon(const llarp::SockAddr& addr) const override
|
||||
{
|
||||
return llarp::IsBogon(addr.asIPv6());
|
||||
}
|
||||
|
||||
bool
|
||||
IsWildcardAddress(ipaddr_t ip) const override
|
||||
{
|
||||
return var::visit([](auto&& ip) { return not ip.n; }, ip);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
// current strategy: mingw 32-bit builds call an inlined version of the function
|
||||
// microsoft c++ and mingw 64-bit builds call the normal function
|
||||
#define DEFAULT_BUFFER_SIZE 15000
|
||||
|
||||
// in any case, we still need to implement some form of
|
||||
// getifaddrs(3) with compatible semantics on NT...
|
||||
// daemon.ini section [bind] will have something like
|
||||
// [bind]
|
||||
// Ethernet=1090
|
||||
// inside, since that's what we use in windows to refer to
|
||||
// network interfaces
|
||||
struct llarp_nt_ifaddrs_t
|
||||
{
|
||||
struct llarp_nt_ifaddrs_t* ifa_next; /* Pointer to the next structure. */
|
||||
char* ifa_name; /* Name of this network interface. */
|
||||
unsigned int ifa_flags; /* Flags as from SIOCGIFFLAGS ioctl. */
|
||||
struct sockaddr* ifa_addr; /* Network address of this interface. */
|
||||
struct sockaddr* ifa_netmask; /* Netmask of this interface. */
|
||||
};
|
||||
|
||||
// internal struct
|
||||
struct _llarp_nt_ifaddrs_t
|
||||
{
|
||||
struct llarp_nt_ifaddrs_t _ifa;
|
||||
char _name[256];
|
||||
struct sockaddr_storage _addr;
|
||||
struct sockaddr_storage _netmask;
|
||||
};
|
||||
|
||||
static inline void*
|
||||
_llarp_nt_heap_alloc(const size_t n_bytes)
|
||||
{
|
||||
/* Does not appear very safe with re-entrant calls on XP */
|
||||
return HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, n_bytes);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_llarp_nt_heap_free(void* mem)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, mem);
|
||||
}
|
||||
#define llarp_nt_new0(struct_type, n_structs) \
|
||||
((struct_type*)malloc((size_t)sizeof(struct_type) * (size_t)(n_structs)))
|
||||
|
||||
int
|
||||
llarp_nt_sockaddr_pton(const char* src, struct sockaddr* dst)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo* result = nullptr;
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
const int status = getaddrinfo(src, nullptr, &hints, &result);
|
||||
if (!status)
|
||||
class Platform_Impl : public Platform_Base
|
||||
{
|
||||
memcpy(dst, result->ai_addr, result->ai_addrlen);
|
||||
freeaddrinfo(result);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NB: IP_ADAPTER_INFO size varies size due to sizeof (time_t), the API assumes
|
||||
* 4-byte datatype whilst compiler uses an 8-byte datatype. Size can be forced
|
||||
* with -D_USE_32BIT_TIME_T with side effects to everything else.
|
||||
*
|
||||
* Only supports IPv4 addressing similar to SIOCGIFCONF socket option.
|
||||
*
|
||||
* Interfaces that are not "operationally up" will return the address 0.0.0.0,
|
||||
* this includes adapters with static IP addresses but with disconnected cable.
|
||||
* This is documented under the GetIpAddrTable API. Interface status can only
|
||||
* be determined by the address, a separate flag is introduced with the
|
||||
* GetAdapterAddresses API.
|
||||
*
|
||||
* The IPv4 loopback interface is not included.
|
||||
*
|
||||
* Available in Windows 2000 and Wine 1.0.
|
||||
*/
|
||||
static bool
|
||||
_llarp_nt_getadaptersinfo(struct llarp_nt_ifaddrs_t** ifap)
|
||||
{
|
||||
DWORD dwRet;
|
||||
ULONG ulOutBufLen = DEFAULT_BUFFER_SIZE;
|
||||
PIP_ADAPTER_INFO pAdapterInfo = nullptr;
|
||||
PIP_ADAPTER_INFO pAdapter = nullptr;
|
||||
|
||||
/* loop to handle interfaces coming online causing a buffer overflow
|
||||
* between first call to list buffer length and second call to enumerate.
|
||||
*/
|
||||
for (unsigned i = 3; i; i--)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "IP_ADAPTER_INFO buffer length %lu bytes.\n", ulOutBufLen);
|
||||
#endif
|
||||
pAdapterInfo = (IP_ADAPTER_INFO*)_llarp_nt_heap_alloc(ulOutBufLen);
|
||||
dwRet = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
|
||||
if (ERROR_BUFFER_OVERFLOW == dwRet)
|
||||
/// visit all adapters (not addresses). windows serves net info per adapter unlink posix which
|
||||
/// gives a list of all distinct addresses.
|
||||
template <typename Visit_t>
|
||||
void
|
||||
iter_adapters(Visit_t&& visit) const
|
||||
{
|
||||
_llarp_nt_heap_free(pAdapterInfo);
|
||||
pAdapterInfo = nullptr;
|
||||
constexpr auto flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST
|
||||
| GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS
|
||||
| GAA_FLAG_INCLUDE_ALL_INTERFACES;
|
||||
|
||||
ULONG sz{};
|
||||
GetAdaptersAddresses(AF_UNSPEC, flags, nullptr, nullptr, &sz);
|
||||
auto* ptr = new uint8_t[sz];
|
||||
auto* addrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(ptr);
|
||||
|
||||
if (auto err = GetAdaptersAddresses(AF_UNSPEC, flags, nullptr, addrs, &sz);
|
||||
err != ERROR_SUCCESS)
|
||||
throw llarp::win32::error{err, "GetAdaptersAddresses()"};
|
||||
|
||||
for (auto* addr = addrs; addr and addr->Next; addr = addr->Next)
|
||||
visit(addr);
|
||||
|
||||
delete[] ptr;
|
||||
}
|
||||
else
|
||||
|
||||
template <typename adapter_t>
|
||||
bool
|
||||
adapter_has_ip(adapter_t* a, ipaddr_t ip) const
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (dwRet)
|
||||
{
|
||||
case ERROR_SUCCESS: /* NO_ERROR */
|
||||
break;
|
||||
case ERROR_BUFFER_OVERFLOW:
|
||||
errno = ENOBUFS;
|
||||
if (pAdapterInfo)
|
||||
_llarp_nt_heap_free(pAdapterInfo);
|
||||
return false;
|
||||
default:
|
||||
errno = dwRet;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "system call failed: %lu\n", GetLastError());
|
||||
#endif
|
||||
if (pAdapterInfo)
|
||||
_llarp_nt_heap_free(pAdapterInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* count valid adapters */
|
||||
int n = 0, k = 0;
|
||||
for (pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next)
|
||||
{
|
||||
for (IP_ADDR_STRING* pIPAddr = &pAdapter->IpAddressList; pIPAddr; pIPAddr = pIPAddr->Next)
|
||||
{
|
||||
/* skip null adapters */
|
||||
if (strlen(pIPAddr->IpAddress.String) == 0)
|
||||
continue;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "GetAdaptersInfo() discovered %d interfaces.\n", n);
|
||||
#endif
|
||||
|
||||
/* contiguous block for adapter list */
|
||||
struct _llarp_nt_ifaddrs_t* ifa = llarp_nt_new0(struct _llarp_nt_ifaddrs_t, n);
|
||||
struct _llarp_nt_ifaddrs_t* ift = ifa;
|
||||
int val = 0;
|
||||
/* now populate list */
|
||||
for (pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next)
|
||||
{
|
||||
for (IP_ADDR_STRING* pIPAddr = &pAdapter->IpAddressList; pIPAddr; pIPAddr = pIPAddr->Next)
|
||||
{
|
||||
/* skip null adapters */
|
||||
if (strlen(pIPAddr->IpAddress.String) == 0)
|
||||
continue;
|
||||
|
||||
/* address */
|
||||
ift->_ifa.ifa_addr = (struct sockaddr*)&ift->_addr;
|
||||
val = llarp_nt_sockaddr_pton(pIPAddr->IpAddress.String, ift->_ifa.ifa_addr);
|
||||
assert(1 == val);
|
||||
|
||||
/* name */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "name:%s IPv4 index:%lu\n", pAdapter->AdapterName, pAdapter->Index);
|
||||
#endif
|
||||
ift->_ifa.ifa_name = ift->_name;
|
||||
StringCchCopyN(ift->_ifa.ifa_name, 128, pAdapter->AdapterName, 128);
|
||||
|
||||
/* flags: assume up, broadcast and multicast */
|
||||
ift->_ifa.ifa_flags = IFF_UP | IFF_BROADCAST | IFF_MULTICAST;
|
||||
if (pAdapter->Type == MIB_IF_TYPE_LOOPBACK)
|
||||
ift->_ifa.ifa_flags |= IFF_LOOPBACK;
|
||||
|
||||
/* netmask */
|
||||
ift->_ifa.ifa_netmask = (sockaddr*)&ift->_netmask;
|
||||
val = llarp_nt_sockaddr_pton(pIPAddr->IpMask.String, ift->_ifa.ifa_netmask);
|
||||
assert(1 == val);
|
||||
|
||||
/* next */
|
||||
if (k++ < (n - 1))
|
||||
for (auto* addr = a->FirstUnicastAddress; addr and addr->Next; addr = addr->Next)
|
||||
{
|
||||
ift->_ifa.ifa_next = (struct llarp_nt_ifaddrs_t*)(ift + 1);
|
||||
ift = (struct _llarp_nt_ifaddrs_t*)(ift->_ifa.ifa_next);
|
||||
SockAddr saddr{*addr->Address.lpSockaddr};
|
||||
if (saddr.getIP() == ip)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename adapter_t>
|
||||
bool
|
||||
adapter_has_fam(adapter_t* a, int af) const
|
||||
{
|
||||
for (auto* addr = a->FirstUnicastAddress; addr and addr->Next; addr = addr->Next)
|
||||
{
|
||||
ift->_ifa.ifa_next = nullptr;
|
||||
SockAddr saddr{*addr->Address.lpSockaddr};
|
||||
if (saddr.Family() == af)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pAdapterInfo)
|
||||
_llarp_nt_heap_free(pAdapterInfo);
|
||||
*ifap = (struct llarp_nt_ifaddrs_t*)ifa;
|
||||
return true;
|
||||
}
|
||||
|
||||
// an implementation of if_nametoindex(3) based on GetAdapterIndex(2)
|
||||
// with a fallback to GetAdaptersAddresses(2) commented out for now
|
||||
// unless it becomes evident that the first codepath fails in certain
|
||||
// edge cases?
|
||||
static unsigned
|
||||
_llarp_nt_nametoindex(const char* ifname)
|
||||
{
|
||||
ULONG ifIndex;
|
||||
DWORD dwRet;
|
||||
char szAdapterName[256];
|
||||
|
||||
if (!ifname)
|
||||
return 0;
|
||||
|
||||
StringCchCopyN(szAdapterName, sizeof(szAdapterName), ifname, 256);
|
||||
dwRet = GetAdapterIndex((LPWSTR)szAdapterName, &ifIndex);
|
||||
|
||||
if (!dwRet)
|
||||
return ifIndex;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// the emulated getifaddrs(3) itself.
|
||||
static bool
|
||||
llarp_nt_getifaddrs(struct llarp_nt_ifaddrs_t** ifap)
|
||||
{
|
||||
assert(nullptr != ifap);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "llarp_nt_getifaddrs (ifap:%p error:%p)\n", (void*)ifap, (void*)errno);
|
||||
#endif
|
||||
return _llarp_nt_getadaptersinfo(ifap);
|
||||
}
|
||||
|
||||
static void
|
||||
llarp_nt_freeifaddrs(struct llarp_nt_ifaddrs_t* ifa)
|
||||
{
|
||||
if (!ifa)
|
||||
return;
|
||||
free(ifa);
|
||||
}
|
||||
|
||||
// emulated if_nametoindex(3)
|
||||
static unsigned
|
||||
llarp_nt_if_nametoindex(const char* ifname)
|
||||
{
|
||||
if (!ifname)
|
||||
return 0;
|
||||
return _llarp_nt_nametoindex(ifname);
|
||||
}
|
||||
|
||||
// fix up names for win32
|
||||
#define ifaddrs llarp_nt_ifaddrs_t
|
||||
#define getifaddrs llarp_nt_getifaddrs
|
||||
#define freeifaddrs llarp_nt_freeifaddrs
|
||||
#define if_nametoindex llarp_nt_if_nametoindex
|
||||
#endif
|
||||
|
||||
// jeff's original code
|
||||
bool
|
||||
llarp_getifaddr(const char* ifname, int af, struct sockaddr* addr)
|
||||
{
|
||||
ifaddrs* ifa = nullptr;
|
||||
bool found = false;
|
||||
socklen_t sl = sizeof(sockaddr_in6);
|
||||
if (af == AF_INET)
|
||||
sl = sizeof(sockaddr_in);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (getifaddrs(&ifa) == -1)
|
||||
#else
|
||||
if (!strcmp(ifname, "lo") || !strcmp(ifname, "lo0"))
|
||||
{
|
||||
if (addr)
|
||||
public:
|
||||
std::optional<int>
|
||||
GetInterfaceIndex(ipaddr_t ip) const override
|
||||
{
|
||||
sockaddr_in* lo = (sockaddr_in*)addr;
|
||||
lo->sin_family = af;
|
||||
lo->sin_port = 0;
|
||||
inet_pton(af, "127.0.0.1", &lo->sin_addr);
|
||||
std::optional<int> found;
|
||||
iter_adapters([&found, ip, this](auto* adapter) {
|
||||
if (found)
|
||||
return;
|
||||
if (adapter_has_ip(adapter, ip))
|
||||
found = adapter->IfIndex;
|
||||
});
|
||||
return found;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!getifaddrs(&ifa))
|
||||
#endif
|
||||
return false;
|
||||
ifaddrs* i = ifa;
|
||||
while (i)
|
||||
{
|
||||
if (i->ifa_addr)
|
||||
|
||||
std::optional<llarp::SockAddr>
|
||||
GetInterfaceAddr(std::string_view name, int af) const override
|
||||
{
|
||||
// llarp::LogInfo(__FILE__, "scanning ", i->ifa_name, " af: ",
|
||||
// std::to_string(i->ifa_addr->sa_family));
|
||||
if (std::string_view{i->ifa_name} == std::string_view{ifname} && i->ifa_addr->sa_family == af)
|
||||
{
|
||||
// can't do this here
|
||||
// llarp::Addr a(*i->ifa_addr);
|
||||
// if(!a.isPrivate())
|
||||
//{
|
||||
// llarp::LogInfo(__FILE__, "found ", ifname, " af: ", af);
|
||||
if (addr)
|
||||
std::optional<SockAddr> found;
|
||||
iter_adapters([name = std::string{name}, af, &found, this](auto* a) {
|
||||
if (found)
|
||||
return;
|
||||
if (std::string{a->AdapterName} != name)
|
||||
return;
|
||||
|
||||
if (adapter_has_fam(a, af))
|
||||
found = SockAddr{*a->FirstUnicastAddress->Address.lpSockaddr};
|
||||
});
|
||||
return found;
|
||||
}
|
||||
|
||||
std::optional<SockAddr>
|
||||
AllInterfaces(SockAddr fallback) const override
|
||||
{
|
||||
// windows seems to not give a shit about source address
|
||||
return fallback.isIPv6() ? SockAddr{"[::]"} : SockAddr{"0.0.0.0"};
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
FindFreeTun() const override
|
||||
{
|
||||
// TODO: implement me ?
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
GetBestNetIF(int) const override
|
||||
{
|
||||
// TODO: implement me ?
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<IPRange>
|
||||
FindFreeRange() const override
|
||||
{
|
||||
std::list<IPRange> currentRanges;
|
||||
iter_adapters([¤tRanges](auto* i) {
|
||||
for (auto* addr = i->FirstUnicastAddress; addr and addr->Next; addr = addr->Next)
|
||||
{
|
||||
memcpy(addr, i->ifa_addr, sl);
|
||||
if (af == AF_INET6)
|
||||
{
|
||||
// set scope id
|
||||
auto* ip6addr = (sockaddr_in6*)addr;
|
||||
ip6addr->sin6_scope_id = if_nametoindex(ifname);
|
||||
ip6addr->sin6_flowinfo = 0;
|
||||
}
|
||||
SockAddr saddr{*addr->Address.lpSockaddr};
|
||||
currentRanges.emplace_back(
|
||||
saddr.asIPv6(),
|
||||
ipaddr_netmask_bits(addr->OnLinkPrefixLength, addr->Address.lpSockaddr->sa_family));
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
//}
|
||||
}
|
||||
i = i->ifa_next;
|
||||
}
|
||||
if (ifa)
|
||||
freeifaddrs(ifa);
|
||||
return found;
|
||||
}
|
||||
});
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
static void
|
||||
IterAllNetworkInterfaces(std::function<void(ifaddrs* const)> visit)
|
||||
{
|
||||
ifaddrs* ifa = nullptr;
|
||||
#ifndef _WIN32
|
||||
if (getifaddrs(&ifa) == -1)
|
||||
#else
|
||||
if (!getifaddrs(&ifa))
|
||||
#endif
|
||||
return;
|
||||
|
||||
ifaddrs* i = ifa;
|
||||
while (i)
|
||||
{
|
||||
visit(i);
|
||||
i = i->ifa_next;
|
||||
}
|
||||
|
||||
if (ifa)
|
||||
freeifaddrs(ifa);
|
||||
}
|
||||
namespace net
|
||||
{
|
||||
std::string
|
||||
LoopbackInterfaceName()
|
||||
{
|
||||
const auto loopback = IPRange::FromIPv4(127, 0, 0, 0, 8);
|
||||
std::string ifname;
|
||||
IterAllNetworkInterfaces([&ifname, loopback](ifaddrs* const i) {
|
||||
if (i->ifa_addr and i->ifa_addr->sa_family == AF_INET)
|
||||
auto ownsRange = [¤tRanges](const IPRange& range) -> bool {
|
||||
for (const auto& ownRange : currentRanges)
|
||||
{
|
||||
llarp::nuint32_t addr{((sockaddr_in*)i->ifa_addr)->sin_addr.s_addr};
|
||||
if (loopback.Contains(xntohl(addr)))
|
||||
if (ownRange * range)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
// generate possible ranges to in order of attempts
|
||||
std::list<IPRange> possibleRanges;
|
||||
for (byte_t oct = 16; oct < 32; ++oct)
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(172, oct, 0, 1, 16));
|
||||
}
|
||||
for (byte_t oct = 0; oct < 255; ++oct)
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(10, oct, 0, 1, 16));
|
||||
}
|
||||
for (byte_t oct = 0; oct < 255; ++oct)
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(192, 168, oct, 1, 24));
|
||||
}
|
||||
// for each possible range pick the first one we don't own
|
||||
for (const auto& range : possibleRanges)
|
||||
{
|
||||
if (not ownsRange(range))
|
||||
return range;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
std::string
|
||||
LoopbackInterfaceName() const override
|
||||
{
|
||||
// todo: implement me? does windows even have a loopback?
|
||||
return "";
|
||||
}
|
||||
bool
|
||||
HasInterfaceAddress(ipaddr_t ip) const override
|
||||
{
|
||||
return GetInterfaceIndex(ip) != std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class Platform_Impl : public Platform_Base
|
||||
{
|
||||
template <typename Visit_t>
|
||||
void
|
||||
iter_all(Visit_t&& visit) const
|
||||
{
|
||||
ifaddrs* addrs{nullptr};
|
||||
if (getifaddrs(&addrs))
|
||||
throw std::runtime_error{fmt::format("getifaddrs(): {}", strerror(errno))};
|
||||
|
||||
for (auto next = addrs; addrs and addrs->ifa_next; addrs = addrs->ifa_next)
|
||||
visit(next);
|
||||
|
||||
freeifaddrs(addrs);
|
||||
}
|
||||
|
||||
public:
|
||||
std::string
|
||||
LoopbackInterfaceName() const override
|
||||
{
|
||||
std::string ifname;
|
||||
iter_all([this, &ifname](auto i) {
|
||||
if (i and i->ifa_addr and i->ifa_addr->sa_family == AF_INET)
|
||||
{
|
||||
const SockAddr addr{*i->ifa_addr};
|
||||
if (IsLoopbackAddress(addr.getIP()))
|
||||
{
|
||||
ifname = i->ifa_name;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (ifname.empty())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"we have no ipv4 loopback interface for some ungodly reason, yeah idk fam");
|
||||
}
|
||||
throw std::runtime_error{"we have no ipv4 loopback interface for some ungodly reason"};
|
||||
return ifname;
|
||||
}
|
||||
} // namespace net
|
||||
|
||||
bool
|
||||
GetBestNetIF(std::string& ifname, int af)
|
||||
{
|
||||
bool found = false;
|
||||
IterAllNetworkInterfaces([&](ifaddrs* i) {
|
||||
if (found)
|
||||
return;
|
||||
if (i->ifa_addr)
|
||||
{
|
||||
if (i->ifa_addr->sa_family == af)
|
||||
{
|
||||
llarp::SockAddr a(*i->ifa_addr);
|
||||
llarp::IpAddress ip(a);
|
||||
|
||||
if (!ip.isBogon())
|
||||
{
|
||||
ifname = i->ifa_name;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return found;
|
||||
}
|
||||
|
||||
// TODO: ipv6?
|
||||
std::optional<IPRange>
|
||||
FindFreeRange()
|
||||
{
|
||||
std::list<IPRange> currentRanges;
|
||||
IterAllNetworkInterfaces([&](ifaddrs* i) {
|
||||
if (i && i->ifa_addr)
|
||||
{
|
||||
const auto fam = i->ifa_addr->sa_family;
|
||||
if (fam != AF_INET)
|
||||
return;
|
||||
auto* addr = (sockaddr_in*)i->ifa_addr;
|
||||
auto* mask = (sockaddr_in*)i->ifa_netmask;
|
||||
nuint32_t ifaddr{addr->sin_addr.s_addr};
|
||||
nuint32_t ifmask{mask->sin_addr.s_addr};
|
||||
#ifdef _WIN32
|
||||
// do not delete, otherwise GCC will do horrible things to this lambda
|
||||
LogDebug("found ", ifaddr, " with mask ", ifmask);
|
||||
#endif
|
||||
if (addr->sin_addr.s_addr)
|
||||
// skip unconfig'd adapters (windows passes these through the unix-y
|
||||
// wrapper)
|
||||
currentRanges.emplace_back(
|
||||
IPRange{net::ExpandV4(xntohl(ifaddr)), net::ExpandV4(xntohl(ifmask))});
|
||||
}
|
||||
});
|
||||
auto ownsRange = [¤tRanges](const IPRange& range) -> bool {
|
||||
for (const auto& ownRange : currentRanges)
|
||||
{
|
||||
if (ownRange * range)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
// generate possible ranges to in order of attempts
|
||||
std::list<IPRange> possibleRanges;
|
||||
for (byte_t oct = 16; oct < 32; ++oct)
|
||||
std::optional<std::string>
|
||||
GetBestNetIF(int af) const override
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(172, oct, 0, 1, 16));
|
||||
}
|
||||
for (byte_t oct = 0; oct < 255; ++oct)
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(10, oct, 0, 1, 16));
|
||||
}
|
||||
for (byte_t oct = 0; oct < 255; ++oct)
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(192, 168, oct, 1, 24));
|
||||
}
|
||||
// for each possible range pick the first one we don't own
|
||||
for (const auto& range : possibleRanges)
|
||||
{
|
||||
if (not ownsRange(range))
|
||||
return range;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
FindFreeTun()
|
||||
{
|
||||
int num = 0;
|
||||
while (num < 255)
|
||||
{
|
||||
std::string iftestname = fmt::format("lokitun{}", num);
|
||||
bool found = llarp_getifaddr(iftestname.c_str(), AF_INET, nullptr);
|
||||
if (!found)
|
||||
{
|
||||
return iftestname;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<SockAddr>
|
||||
GetInterfaceAddr(const std::string& ifname, int af)
|
||||
{
|
||||
sockaddr_storage s;
|
||||
sockaddr* sptr = (sockaddr*)&s;
|
||||
sptr->sa_family = af;
|
||||
if (!llarp_getifaddr(ifname.c_str(), af, sptr))
|
||||
return std::nullopt;
|
||||
return SockAddr{*sptr};
|
||||
}
|
||||
|
||||
std::optional<huint128_t>
|
||||
GetInterfaceIPv6Address(std::string ifname)
|
||||
{
|
||||
sockaddr_storage s;
|
||||
sockaddr* sptr = (sockaddr*)&s;
|
||||
sptr->sa_family = AF_INET6;
|
||||
if (!llarp_getifaddr(ifname.c_str(), AF_INET6, sptr))
|
||||
return std::nullopt;
|
||||
llarp::SockAddr addr{*sptr};
|
||||
return addr.asIPv6();
|
||||
}
|
||||
|
||||
namespace net
|
||||
{
|
||||
namespace
|
||||
{
|
||||
SockAddr
|
||||
All(int af)
|
||||
{
|
||||
if (af == AF_INET)
|
||||
{
|
||||
sockaddr_in addr{};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(0);
|
||||
return SockAddr{addr};
|
||||
}
|
||||
if (af == AF_INET6)
|
||||
{
|
||||
sockaddr_in6 addr6{};
|
||||
addr6.sin6_family = AF_INET6;
|
||||
addr6.sin6_port = htons(0);
|
||||
addr6.sin6_addr = IN6ADDR_ANY_INIT;
|
||||
return SockAddr{addr6};
|
||||
}
|
||||
throw std::invalid_argument{fmt::format("{} is not a valid address family", af)};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::optional<SockAddr>
|
||||
AllInterfaces(SockAddr pub)
|
||||
{
|
||||
std::optional<SockAddr> found;
|
||||
IterAllNetworkInterfaces([pub, &found](auto* ifa) {
|
||||
std::optional<std::string> found;
|
||||
iter_all([this, &found, af](auto i) {
|
||||
if (found)
|
||||
return;
|
||||
if (auto ifa_addr = ifa->ifa_addr)
|
||||
if (i and i->ifa_addr and i->ifa_addr->sa_family == af)
|
||||
{
|
||||
if (ifa_addr->sa_family != pub.Family())
|
||||
return;
|
||||
|
||||
SockAddr addr{*ifa->ifa_addr};
|
||||
|
||||
if (addr == pub)
|
||||
found = addr;
|
||||
if (not IsBogon(*i->ifa_addr))
|
||||
{
|
||||
found = i->ifa_name;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
std::optional<IPRange>
|
||||
FindFreeRange() const override
|
||||
{
|
||||
std::list<IPRange> currentRanges;
|
||||
iter_all([¤tRanges](auto i) {
|
||||
if (i and i->ifa_addr and i->ifa_addr->sa_family == AF_INET)
|
||||
{
|
||||
ipv4addr_t addr{reinterpret_cast<sockaddr_in*>(i->ifa_addr)->sin_addr.s_addr};
|
||||
ipv4addr_t mask{reinterpret_cast<sockaddr_in*>(i->ifa_netmask)->sin_addr.s_addr};
|
||||
currentRanges.emplace_back(IPRange::FromIPv4(addr, mask));
|
||||
}
|
||||
});
|
||||
|
||||
auto ownsRange = [¤tRanges](const IPRange& range) -> bool {
|
||||
for (const auto& ownRange : currentRanges)
|
||||
{
|
||||
if (ownRange * range)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
// generate possible ranges to in order of attempts
|
||||
std::list<IPRange> possibleRanges;
|
||||
for (byte_t oct = 16; oct < 32; ++oct)
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(172, oct, 0, 1, 16));
|
||||
}
|
||||
for (byte_t oct = 0; oct < 255; ++oct)
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(10, oct, 0, 1, 16));
|
||||
}
|
||||
for (byte_t oct = 0; oct < 255; ++oct)
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(192, 168, oct, 1, 24));
|
||||
}
|
||||
// for each possible range pick the first one we don't own
|
||||
for (const auto& range : possibleRanges)
|
||||
{
|
||||
if (not ownsRange(range))
|
||||
return range;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<int> GetInterfaceIndex(ipaddr_t) const override
|
||||
{
|
||||
// todo: implement me
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
FindFreeTun() const override
|
||||
{
|
||||
int num = 0;
|
||||
while (num < 255)
|
||||
{
|
||||
std::string ifname = fmt::format("lokitun{}", num);
|
||||
if (GetInterfaceAddr(ifname, AF_INET))
|
||||
return ifname;
|
||||
num++;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<SockAddr>
|
||||
GetInterfaceAddr(std::string_view ifname, int af) const override
|
||||
{
|
||||
std::optional<SockAddr> addr;
|
||||
iter_all([&addr, af, ifname = std::string{ifname}](auto i) {
|
||||
if (addr)
|
||||
return;
|
||||
if (i and i->ifa_addr and i->ifa_addr->sa_family == af and i->ifa_name == ifname)
|
||||
addr = llarp::SockAddr{*i->ifa_addr};
|
||||
});
|
||||
return addr;
|
||||
}
|
||||
|
||||
std::optional<SockAddr>
|
||||
AllInterfaces(SockAddr fallback) const override
|
||||
{
|
||||
std::optional<SockAddr> found;
|
||||
iter_all([fallback, &found](auto i) {
|
||||
if (found)
|
||||
return;
|
||||
if (i == nullptr or i->ifa_addr == nullptr)
|
||||
return;
|
||||
if (i->ifa_addr->sa_family != fallback.Family())
|
||||
return;
|
||||
SockAddr addr{*i->ifa_addr};
|
||||
if (addr == fallback)
|
||||
found = addr;
|
||||
});
|
||||
|
||||
// 0.0.0.0 is used in our compat shim as our public ip so we check for that special case
|
||||
const auto zero = IPRange::FromIPv4(0, 0, 0, 0, 8);
|
||||
// when we cannot find an address but we are looking for 0.0.0.0 just default to the old style
|
||||
if (not found and (pub.isIPv4() and zero.Contains(pub.asIPv4())))
|
||||
found = All(pub.Family());
|
||||
// when we cannot find an address but we are looking for 0.0.0.0 just default to the old
|
||||
// style
|
||||
if (not found and (fallback.isIPv4() and zero.Contains(fallback.asIPv4())))
|
||||
found = Wildcard(fallback.Family());
|
||||
return found;
|
||||
}
|
||||
} // namespace net
|
||||
|
||||
bool
|
||||
HasInterfaceAddress(ipaddr_t ip) const override
|
||||
{
|
||||
bool found{false};
|
||||
iter_all([&found, ip](auto i) {
|
||||
if (found)
|
||||
return;
|
||||
|
||||
if (not(i and i->ifa_addr))
|
||||
return;
|
||||
const SockAddr addr{*i->ifa_addr};
|
||||
found = addr.getIP() == ip;
|
||||
});
|
||||
return found;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
const Platform_Impl g_plat{};
|
||||
|
||||
const Platform*
|
||||
Platform::Default_ptr()
|
||||
{
|
||||
return &g_plat;
|
||||
}
|
||||
} // namespace llarp::net
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
#if !defined(TESTNET)
|
||||
static constexpr std::array bogonRanges_v6 = {
|
||||
// zero
|
||||
|
@ -721,20 +575,5 @@ namespace llarp
|
|||
return false;
|
||||
}
|
||||
#endif
|
||||
bool
|
||||
HasInterfaceAddress(std::variant<nuint32_t, nuint128_t> ip)
|
||||
{
|
||||
bool found{false};
|
||||
IterAllNetworkInterfaces([ip, &found](const auto* iface) {
|
||||
if (found or iface == nullptr)
|
||||
return;
|
||||
if (auto addr = iface->ifa_addr;
|
||||
addr and (addr->sa_family == AF_INET or addr->sa_family == AF_INET6))
|
||||
{
|
||||
found = SockAddr{*iface->ifa_addr}.getIP() == ip;
|
||||
}
|
||||
});
|
||||
return found;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
||||
|
|
|
@ -67,56 +67,89 @@ namespace llarp
|
|||
bool
|
||||
IsBogonRange(const in6_addr& host, const in6_addr& mask);
|
||||
|
||||
/// get a sock addr we can use for all interfaces given our public address
|
||||
namespace net
|
||||
{
|
||||
std::optional<SockAddr>
|
||||
AllInterfaces(SockAddr pubaddr);
|
||||
}
|
||||
|
||||
/// compat shim
|
||||
// TODO: remove me
|
||||
inline bool
|
||||
AllInterfaces(int af, SockAddr& addr)
|
||||
{
|
||||
if (auto maybe = net::AllInterfaces(SockAddr{af == AF_INET ? "0.0.0.0" : "::"}))
|
||||
/// network platform (all methods virtual so it can be mocked by unit tests)
|
||||
class Platform
|
||||
{
|
||||
addr = *maybe;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public:
|
||||
Platform() = default;
|
||||
virtual ~Platform() = default;
|
||||
Platform(const Platform&) = delete;
|
||||
Platform(Platform&&) = delete;
|
||||
|
||||
/// get first network interface with public address
|
||||
bool
|
||||
GetBestNetIF(std::string& ifname, int af = AF_INET);
|
||||
/// get a pointer to our signleton instance used by main lokinet
|
||||
/// unit test mocks will not call this
|
||||
static const Platform*
|
||||
Default_ptr();
|
||||
|
||||
/// look at adapter ranges and find a free one
|
||||
std::optional<IPRange>
|
||||
FindFreeRange();
|
||||
virtual std::optional<SockAddr>
|
||||
AllInterfaces(SockAddr pubaddr) const = 0;
|
||||
|
||||
/// look at adapter names and find a free one
|
||||
std::optional<std::string>
|
||||
FindFreeTun();
|
||||
virtual SockAddr
|
||||
Wildcard(int af = AF_INET) const = 0;
|
||||
|
||||
/// get network interface address for network interface with ifname
|
||||
std::optional<SockAddr>
|
||||
GetInterfaceAddr(const std::string& ifname, int af = AF_INET);
|
||||
inline SockAddr
|
||||
WildcardWithPort(port_t port, int af = AF_INET) const
|
||||
{
|
||||
auto addr = Wildcard(af);
|
||||
addr.setPort(port);
|
||||
return addr;
|
||||
}
|
||||
|
||||
/// get an interface's ip6 address
|
||||
std::optional<huint128_t>
|
||||
GetInterfaceIPv6Address(std::string ifname);
|
||||
virtual std::string
|
||||
LoopbackInterfaceName() const = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
namespace net
|
||||
{
|
||||
std::optional<int>
|
||||
GetInterfaceIndex(huint32_t ip);
|
||||
}
|
||||
#endif
|
||||
virtual bool
|
||||
HasInterfaceAddress(ipaddr_t ip) const = 0;
|
||||
|
||||
/// return true if we have a network interface with this ip
|
||||
bool
|
||||
HasInterfaceAddress(std::variant<nuint32_t, nuint128_t> ip);
|
||||
/// return true if ip is considered a loopback address
|
||||
virtual bool
|
||||
IsLoopbackAddress(ipaddr_t ip) const = 0;
|
||||
|
||||
/// return true if ip is considered a wildcard address
|
||||
virtual bool
|
||||
IsWildcardAddress(ipaddr_t ip) const = 0;
|
||||
|
||||
virtual std::optional<std::string>
|
||||
GetBestNetIF(int af = AF_INET) const = 0;
|
||||
|
||||
inline std::optional<SockAddr>
|
||||
MaybeInferPublicAddr(port_t default_port, int af = AF_INET) const
|
||||
{
|
||||
std::optional<SockAddr> maybe_addr;
|
||||
if (auto maybe_ifname = GetBestNetIF(af))
|
||||
maybe_addr = GetInterfaceAddr(*maybe_ifname, af);
|
||||
|
||||
if (maybe_addr)
|
||||
maybe_addr->setPort(default_port);
|
||||
return maybe_addr;
|
||||
}
|
||||
|
||||
virtual std::optional<IPRange>
|
||||
FindFreeRange() const = 0;
|
||||
|
||||
virtual std::optional<std::string>
|
||||
FindFreeTun() const = 0;
|
||||
|
||||
virtual std::optional<SockAddr>
|
||||
GetInterfaceAddr(std::string_view ifname, int af = AF_INET) const = 0;
|
||||
|
||||
inline std::optional<huint128_t>
|
||||
GetInterfaceIPv6Address(std::string_view ifname) const
|
||||
{
|
||||
if (auto maybe_addr = GetInterfaceAddr(ifname, AF_INET6))
|
||||
return maybe_addr->asIPv6();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
IsBogon(const SockAddr& addr) const = 0;
|
||||
|
||||
virtual std::optional<int>
|
||||
GetInterfaceIndex(ipaddr_t ip) const = 0;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
||||
} // namespace llarp
|
||||
|
|
|
@ -48,4 +48,14 @@ namespace llarp
|
|||
return false;
|
||||
return true;
|
||||
}
|
||||
namespace net
|
||||
{
|
||||
inline auto
|
||||
ipaddr_netmask_bits(uint32_t bits, int af)
|
||||
{
|
||||
if (af == AF_INET6)
|
||||
return netmask_ipv6_bits(bits);
|
||||
return ExpandV4(netmask_ipv4_bits(bits));
|
||||
};
|
||||
} // namespace net
|
||||
} // namespace llarp
|
||||
|
|
|
@ -6,41 +6,44 @@
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
huint16_t
|
||||
ToHost(nuint16_t n)
|
||||
namespace net
|
||||
{
|
||||
return xntohs(n);
|
||||
}
|
||||
huint16_t
|
||||
ToHost(port_t x)
|
||||
{
|
||||
return huint16_t{oxenc::big_to_host(x.n)};
|
||||
}
|
||||
|
||||
huint32_t
|
||||
ToHost(nuint32_t n)
|
||||
{
|
||||
return xntohl(n);
|
||||
}
|
||||
huint32_t
|
||||
ToHost(ipv4addr_t x)
|
||||
{
|
||||
return huint32_t{oxenc::big_to_host(x.n)};
|
||||
}
|
||||
|
||||
huint128_t
|
||||
ToHost(nuint128_t n)
|
||||
{
|
||||
return {ntoh128(n.n)};
|
||||
}
|
||||
huint128_t
|
||||
ToHost(ipv6addr_t x)
|
||||
{
|
||||
return {ntoh128(x.n)};
|
||||
}
|
||||
|
||||
nuint16_t
|
||||
ToNet(huint16_t h)
|
||||
{
|
||||
return xhtons(h);
|
||||
}
|
||||
port_t
|
||||
ToNet(huint16_t x)
|
||||
{
|
||||
return port_t{oxenc::host_to_big(x.h)};
|
||||
}
|
||||
|
||||
nuint32_t
|
||||
ToNet(huint32_t h)
|
||||
{
|
||||
return xhtonl(h);
|
||||
}
|
||||
ipv4addr_t
|
||||
ToNet(huint32_t x)
|
||||
{
|
||||
return ipv4addr_t{oxenc::host_to_big(x.h)};
|
||||
}
|
||||
|
||||
nuint128_t
|
||||
ToNet(huint128_t h)
|
||||
{
|
||||
return {hton128(h.h)};
|
||||
}
|
||||
ipv6addr_t
|
||||
ToNet(huint128_t x)
|
||||
{
|
||||
return ipv6addr_t{hton128(x.h)};
|
||||
}
|
||||
} // namespace net
|
||||
|
||||
template <>
|
||||
void
|
||||
|
@ -128,6 +131,17 @@ namespace llarp
|
|||
return "";
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string
|
||||
nuint128_t::ToString() const
|
||||
{
|
||||
char tmp[INET6_ADDRSTRLEN] = {0};
|
||||
if (!inet_ntop(AF_INET6, (void*)&n, tmp, sizeof(tmp)))
|
||||
return "";
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string
|
||||
huint16_t::ToString() const
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include <llarp/util/formattable.hpp>
|
||||
#include <oxenc/variant.h>
|
||||
|
||||
#include "uint128.hpp"
|
||||
|
||||
|
@ -105,7 +106,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
using V6Container = std::vector<uint8_t>;
|
||||
void
|
||||
[[deprecated]] void
|
||||
ToV6(V6Container& c);
|
||||
|
||||
std::string
|
||||
|
@ -174,7 +175,7 @@ namespace llarp
|
|||
}
|
||||
|
||||
using V6Container = std::vector<uint8_t>;
|
||||
void
|
||||
[[deprecated]] void
|
||||
ToV6(V6Container& c);
|
||||
|
||||
std::string
|
||||
|
@ -189,49 +190,86 @@ namespace llarp
|
|||
*this = ToNet(x);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline static nuint_t<UInt_t>
|
||||
from_string(const std::string& str)
|
||||
{
|
||||
nuint_t<UInt_t> x{};
|
||||
if (not x.FromString(str))
|
||||
throw std::invalid_argument{fmt::format("{} is not a valid value")};
|
||||
return x;
|
||||
}
|
||||
|
||||
template <typename... Args_t>
|
||||
inline static nuint_t<UInt_t>
|
||||
from_host(Args_t&&... args)
|
||||
{
|
||||
return ToNet(huint_t<UInt_t>{std::forward<Args_t>(args)...});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename UInt_t>
|
||||
inline constexpr bool IsToStringFormattable<huint_t<UInt_t>> = true;
|
||||
namespace net
|
||||
{
|
||||
/// hides the nuint types used with net_port_t / net_ipv4addr_t / net_ipv6addr_t
|
||||
namespace
|
||||
{
|
||||
using n_uint16_t = llarp::nuint_t<uint16_t>;
|
||||
using n_uint32_t = llarp::nuint_t<uint32_t>;
|
||||
using n_uint128_t = llarp::nuint_t<llarp::uint128_t>;
|
||||
} // namespace
|
||||
|
||||
using port_t = n_uint16_t;
|
||||
using ipv4addr_t = n_uint32_t;
|
||||
using flowlabel_t = n_uint32_t;
|
||||
using ipv6addr_t = n_uint128_t;
|
||||
using ipaddr_t = std::variant<ipv4addr_t, ipv6addr_t>;
|
||||
|
||||
huint16_t ToHost(port_t);
|
||||
huint32_t ToHost(ipv4addr_t);
|
||||
huint128_t ToHost(ipv6addr_t);
|
||||
|
||||
port_t ToNet(huint16_t);
|
||||
ipv4addr_t ToNet(huint32_t);
|
||||
ipv6addr_t ToNet(huint128_t);
|
||||
|
||||
} // namespace net
|
||||
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<huint128_t> = true;
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<huint32_t> = true;
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<huint16_t> = true;
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<net::ipv6addr_t> = true;
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<net::ipv4addr_t> = true;
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<net::port_t> = true;
|
||||
|
||||
using nuint16_t [[deprecated("use llarp::net::port_t instead")]] = llarp::net::port_t;
|
||||
using nuint32_t [[deprecated("use llarp::net::ipv4addr_t instead")]] = llarp::net::ipv4addr_t;
|
||||
using nuint128_t [[deprecated("use llarp::net::ipv6addr_t instead")]] = llarp::net::ipv6addr_t;
|
||||
|
||||
template <typename UInt_t>
|
||||
inline constexpr bool IsToStringFormattable<nuint_t<UInt_t>> = true;
|
||||
[[deprecated("use llarp::net::ToNet instead")]] inline llarp::nuint_t<UInt_t>
|
||||
ToNet(llarp::huint_t<UInt_t> x)
|
||||
{
|
||||
return llarp::net::ToNet(x);
|
||||
}
|
||||
|
||||
using nuint32_t = nuint_t<uint32_t>;
|
||||
using nuint16_t = nuint_t<uint16_t>;
|
||||
using nuint128_t = nuint_t<llarp::uint128_t>;
|
||||
template <typename UInt_t>
|
||||
[[deprecated("use llarp::net::ToHost instead")]] inline llarp::huint_t<UInt_t>
|
||||
ToHost(llarp::nuint_t<UInt_t> x)
|
||||
{
|
||||
return llarp::net::ToHost(x);
|
||||
}
|
||||
|
||||
static inline nuint32_t
|
||||
[[deprecated("use llarp::net::ToHost instead")]] inline net::ipv4addr_t
|
||||
xhtonl(huint32_t x)
|
||||
{
|
||||
return nuint32_t{htonl(x.h)};
|
||||
return ToNet(x);
|
||||
}
|
||||
|
||||
static inline huint32_t
|
||||
xntohl(nuint32_t x)
|
||||
{
|
||||
return huint32_t{ntohl(x.n)};
|
||||
}
|
||||
|
||||
static inline nuint16_t
|
||||
xhtons(huint16_t x)
|
||||
{
|
||||
return nuint16_t{htons(x.h)};
|
||||
}
|
||||
|
||||
static inline huint16_t
|
||||
xntohs(nuint16_t x)
|
||||
{
|
||||
return huint16_t{ntohs(x.n)};
|
||||
}
|
||||
|
||||
huint16_t ToHost(nuint16_t);
|
||||
huint32_t ToHost(nuint32_t);
|
||||
huint128_t ToHost(nuint128_t);
|
||||
|
||||
nuint16_t ToNet(huint16_t);
|
||||
nuint32_t ToNet(huint32_t);
|
||||
nuint128_t ToNet(huint128_t);
|
||||
} // namespace llarp
|
||||
|
||||
namespace std
|
||||
|
|
|
@ -101,6 +101,15 @@ namespace llarp
|
|||
void
|
||||
setIPv4(uint8_t a, uint8_t b, uint8_t c, uint8_t d);
|
||||
|
||||
inline void
|
||||
setIP(std::variant<nuint32_t, nuint128_t> ip)
|
||||
{
|
||||
if (auto* v4 = std::get_if<nuint32_t>(&ip))
|
||||
setIPv4(*v4);
|
||||
if (auto* v6 = std::get_if<nuint128_t>(&ip))
|
||||
setIPv6(*v6);
|
||||
}
|
||||
|
||||
void
|
||||
setIPv4(nuint32_t ip);
|
||||
|
||||
|
@ -143,6 +152,7 @@ namespace llarp
|
|||
getIPv6() const;
|
||||
nuint32_t
|
||||
getIPv4() const;
|
||||
|
||||
std::variant<nuint32_t, nuint128_t>
|
||||
getIP() const;
|
||||
|
||||
|
|
|
@ -45,6 +45,11 @@ namespace llarp
|
|||
struct I_RCLookupHandler;
|
||||
struct RoutePoker;
|
||||
|
||||
namespace net
|
||||
{
|
||||
class Platform;
|
||||
}
|
||||
|
||||
namespace exit
|
||||
{
|
||||
struct Context;
|
||||
|
@ -93,6 +98,9 @@ namespace llarp
|
|||
virtual bool
|
||||
HandleRecvLinkMessageBuffer(ILinkSession* from, const llarp_buffer_t& msg) = 0;
|
||||
|
||||
virtual const net::Platform&
|
||||
Net() const = 0;
|
||||
|
||||
virtual const LMQ_ptr&
|
||||
lmq() const = 0;
|
||||
|
||||
|
@ -346,10 +354,8 @@ namespace llarp
|
|||
HandleRouterEvent(std::move(event));
|
||||
}
|
||||
|
||||
#if defined(ANDROID)
|
||||
virtual int
|
||||
GetOutboundUDPSocket() const = 0;
|
||||
#endif
|
||||
OutboundUDPSocket() const = 0;
|
||||
|
||||
protected:
|
||||
/// Virtual function to handle RouterEvent. HiveRouter overrides this in
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
#include <llarp/constants/platform.hpp>
|
||||
|
||||
#include <oxenmq/oxenmq.h>
|
||||
|
||||
static constexpr std::chrono::milliseconds ROUTER_TICK_INTERVAL = 250ms;
|
||||
|
@ -580,8 +582,6 @@ namespace llarp
|
|||
_rc.netID = llarp::NetID();
|
||||
}
|
||||
|
||||
// IWP config
|
||||
m_OutboundPort = conf.links.m_OutboundLink.port;
|
||||
// Router config
|
||||
_rc.SetNick(conf.router.m_nickname);
|
||||
_outboundSessionMaker.maxConnectedRouters = conf.router.m_maxConnectedRouters;
|
||||
|
@ -592,8 +592,20 @@ namespace llarp
|
|||
transport_keyfile = m_keyManager->m_transportKeyPath;
|
||||
ident_keyfile = m_keyManager->m_idKeyPath;
|
||||
|
||||
if (auto maybe = conf.router.m_PublicIP)
|
||||
_ourAddress = SockAddr{*maybe, conf.router.m_PublicPort};
|
||||
if (auto maybe_ip = conf.links.PublicAddress)
|
||||
_ourAddress = var::visit([](auto&& ip) { return SockAddr{ip}; }, *maybe_ip);
|
||||
else if (auto maybe_ip = conf.router.PublicIP)
|
||||
_ourAddress = var::visit([](auto&& ip) { return SockAddr{ip}; }, *maybe_ip);
|
||||
|
||||
if (_ourAddress)
|
||||
{
|
||||
if (auto maybe_port = conf.links.PublicPort)
|
||||
_ourAddress->setPort(*maybe_port);
|
||||
else if (auto maybe_port = conf.router.PublicPort)
|
||||
_ourAddress->setPort(*maybe_port);
|
||||
else
|
||||
throw std::runtime_error{"public ip provided without public port"};
|
||||
}
|
||||
|
||||
RouterContact::BlockBogons = conf.router.m_blockBogons;
|
||||
|
||||
|
@ -720,48 +732,10 @@ namespace llarp
|
|||
whitelistRouters,
|
||||
m_isServiceNode);
|
||||
|
||||
std::vector<LinksConfig::LinkInfo> inboundLinks = conf.links.m_InboundLinks;
|
||||
|
||||
if (inboundLinks.empty() and m_isServiceNode)
|
||||
{
|
||||
if (_ourAddress)
|
||||
{
|
||||
inboundLinks.push_back(LinksConfig::LinkInfo{
|
||||
_ourAddress->hostString(), _ourAddress->Family(), _ourAddress->getPort()});
|
||||
}
|
||||
else
|
||||
throw std::runtime_error{
|
||||
"service node enabled but could not find a public IP to bind to; you need to set the "
|
||||
"public-ip= and public-port= options"};
|
||||
}
|
||||
|
||||
// create inbound links, if we are a service node
|
||||
for (const LinksConfig::LinkInfo& serverConfig : inboundLinks)
|
||||
{
|
||||
auto server = iwp::NewInboundLink(
|
||||
m_keyManager,
|
||||
loop(),
|
||||
util::memFn(&AbstractRouter::rc, this),
|
||||
util::memFn(&AbstractRouter::HandleRecvLinkMessageBuffer, this),
|
||||
util::memFn(&AbstractRouter::Sign, this),
|
||||
nullptr,
|
||||
util::memFn(&Router::ConnectionEstablished, this),
|
||||
util::memFn(&AbstractRouter::CheckRenegotiateValid, this),
|
||||
util::memFn(&Router::ConnectionTimedOut, this),
|
||||
util::memFn(&AbstractRouter::SessionClosed, this),
|
||||
util::memFn(&AbstractRouter::TriggerPump, this),
|
||||
util::memFn(&AbstractRouter::QueueWork, this));
|
||||
|
||||
const std::string& key = serverConfig.m_interface;
|
||||
int af = serverConfig.addressFamily;
|
||||
uint16_t port = serverConfig.port;
|
||||
if (!server->Configure(this, key, af, port))
|
||||
{
|
||||
throw std::runtime_error{
|
||||
fmt::format("failed to bind inbound link on {} port {}", key, port)};
|
||||
}
|
||||
_linkManager.AddLink(std::move(server), true);
|
||||
}
|
||||
// inbound links
|
||||
InitInboundLinks();
|
||||
// outbound links
|
||||
InitOutboundLinks();
|
||||
|
||||
// profiling
|
||||
_profilesFile = conf.router.m_dataDir / "profiles.dat";
|
||||
|
@ -1216,6 +1190,12 @@ namespace llarp
|
|||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
Router::OutboundUDPSocket() const
|
||||
{
|
||||
return m_OutboundUDPSocket;
|
||||
}
|
||||
|
||||
bool
|
||||
Router::Run()
|
||||
{
|
||||
|
@ -1234,13 +1214,20 @@ namespace llarp
|
|||
AddressInfo ai;
|
||||
if (link->GetOurAddressInfo(ai))
|
||||
{
|
||||
// override ip and port
|
||||
// override ip and port as needed
|
||||
if (_ourAddress)
|
||||
{
|
||||
if (not Net().IsBogon(ai.ip))
|
||||
throw std::runtime_error{"cannot override public ip, it is already set"};
|
||||
ai.fromSockAddr(*_ourAddress);
|
||||
}
|
||||
if (RouterContact::BlockBogons && IsBogon(ai.ip))
|
||||
return;
|
||||
throw std::runtime_error{var::visit(
|
||||
[](auto&& ip) {
|
||||
return "cannot use " + ip.ToString()
|
||||
+ " as a public ip as it is in a non routable ip range";
|
||||
},
|
||||
ai.IP())};
|
||||
LogInfo("adding address: ", ai);
|
||||
_rc.addrs.push_back(ai);
|
||||
}
|
||||
|
@ -1268,12 +1255,6 @@ namespace llarp
|
|||
return false;
|
||||
}
|
||||
|
||||
if (not InitOutboundLinks())
|
||||
{
|
||||
LogError("failed to init outbound links");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsServiceNode())
|
||||
{
|
||||
if (!SaveRC())
|
||||
|
@ -1603,47 +1584,116 @@ namespace llarp
|
|||
return found;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
Router::InitInboundLinks()
|
||||
{
|
||||
auto addrs = m_Config->links.InboundListenAddrs;
|
||||
if (m_isServiceNode and addrs.empty())
|
||||
{
|
||||
LogInfo("Inferring Public Address");
|
||||
|
||||
auto maybe_port = m_Config->links.PublicPort;
|
||||
if (m_Config->router.PublicPort and not maybe_port)
|
||||
maybe_port = m_Config->router.PublicPort;
|
||||
if (not maybe_port)
|
||||
maybe_port = net::port_t::from_host(constants::DefaultInboundIWPPort);
|
||||
|
||||
if (auto maybe_addr = Net().MaybeInferPublicAddr(*maybe_port))
|
||||
{
|
||||
LogInfo("Public Address looks to be ", *maybe_addr);
|
||||
addrs.emplace_back(std::move(*maybe_addr));
|
||||
}
|
||||
}
|
||||
if (m_isServiceNode and addrs.empty())
|
||||
throw std::runtime_error{"we are a service node and we have no inbound links configured"};
|
||||
|
||||
// create inbound links, if we are a service node
|
||||
for (auto bind_addr : addrs)
|
||||
{
|
||||
if (bind_addr.getPort() == 0)
|
||||
throw std::invalid_argument{"inbound link cannot use port 0"};
|
||||
|
||||
if (Net().IsWildcardAddress(bind_addr.getIP()))
|
||||
{
|
||||
if (auto maybe_ip = OurPublicIP())
|
||||
bind_addr.setIP(*maybe_ip);
|
||||
else
|
||||
throw std::runtime_error{"no public ip provided for inbound socket"};
|
||||
}
|
||||
|
||||
auto server = iwp::NewInboundLink(
|
||||
m_keyManager,
|
||||
loop(),
|
||||
util::memFn(&AbstractRouter::rc, this),
|
||||
util::memFn(&AbstractRouter::HandleRecvLinkMessageBuffer, this),
|
||||
util::memFn(&AbstractRouter::Sign, this),
|
||||
nullptr,
|
||||
util::memFn(&Router::ConnectionEstablished, this),
|
||||
util::memFn(&AbstractRouter::CheckRenegotiateValid, this),
|
||||
util::memFn(&Router::ConnectionTimedOut, this),
|
||||
util::memFn(&AbstractRouter::SessionClosed, this),
|
||||
util::memFn(&AbstractRouter::TriggerPump, this),
|
||||
util::memFn(&AbstractRouter::QueueWork, this));
|
||||
|
||||
server->Bind(this, bind_addr);
|
||||
_linkManager.AddLink(std::move(server), true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Router::InitOutboundLinks()
|
||||
{
|
||||
auto link = iwp::NewOutboundLink(
|
||||
m_keyManager,
|
||||
loop(),
|
||||
util::memFn(&AbstractRouter::rc, this),
|
||||
util::memFn(&AbstractRouter::HandleRecvLinkMessageBuffer, this),
|
||||
util::memFn(&AbstractRouter::Sign, this),
|
||||
[&](llarp::RouterContact rc) {
|
||||
if (IsServiceNode())
|
||||
return;
|
||||
llarp::LogTrace(
|
||||
"Before connect, outbound link adding route to (",
|
||||
rc.addrs[0].toIpAddress().toIP(),
|
||||
") via gateway.");
|
||||
m_RoutePoker.AddRoute(rc.addrs[0].toIpAddress().toIP());
|
||||
},
|
||||
util::memFn(&Router::ConnectionEstablished, this),
|
||||
util::memFn(&AbstractRouter::CheckRenegotiateValid, this),
|
||||
util::memFn(&Router::ConnectionTimedOut, this),
|
||||
util::memFn(&AbstractRouter::SessionClosed, this),
|
||||
util::memFn(&AbstractRouter::TriggerPump, this),
|
||||
util::memFn(&AbstractRouter::QueueWork, this));
|
||||
auto addrs = m_Config->links.OutboundLinks;
|
||||
if (addrs.empty())
|
||||
addrs.emplace_back(Net().Wildcard());
|
||||
|
||||
if (!link)
|
||||
throw std::runtime_error("NewOutboundLink() failed to provide a link");
|
||||
|
||||
for (const auto af : {AF_INET, AF_INET6})
|
||||
for (auto bind_addr : addrs)
|
||||
{
|
||||
if (not link->Configure(this, "*", af, m_OutboundPort))
|
||||
continue;
|
||||
auto link = iwp::NewOutboundLink(
|
||||
m_keyManager,
|
||||
loop(),
|
||||
util::memFn(&AbstractRouter::rc, this),
|
||||
util::memFn(&AbstractRouter::HandleRecvLinkMessageBuffer, this),
|
||||
util::memFn(&AbstractRouter::Sign, this),
|
||||
[this](llarp::RouterContact rc) {
|
||||
if (IsServiceNode())
|
||||
return;
|
||||
llarp::LogTrace(
|
||||
"Before connect, outbound link adding route to (",
|
||||
rc.addrs[0].toIpAddress().toIP(),
|
||||
") via gateway.");
|
||||
m_RoutePoker.AddRoute(rc.addrs[0].toIpAddress().toIP());
|
||||
},
|
||||
util::memFn(&Router::ConnectionEstablished, this),
|
||||
util::memFn(&AbstractRouter::CheckRenegotiateValid, this),
|
||||
util::memFn(&Router::ConnectionTimedOut, this),
|
||||
util::memFn(&AbstractRouter::SessionClosed, this),
|
||||
util::memFn(&AbstractRouter::TriggerPump, this),
|
||||
util::memFn(&AbstractRouter::QueueWork, this));
|
||||
|
||||
const auto& net = Net();
|
||||
|
||||
// try to use a public address if we have one set on our inbound links
|
||||
_linkManager.ForEachInboundLink([&bind_addr, &net](const auto& link) {
|
||||
if (not net.IsBogon(bind_addr))
|
||||
return;
|
||||
if (auto addr = link->LocalSocketAddr(); not net.IsBogon(addr))
|
||||
bind_addr.setIP(addr.getIP());
|
||||
});
|
||||
|
||||
link->Bind(this, bind_addr);
|
||||
|
||||
if constexpr (llarp::platform::is_android)
|
||||
m_OutboundUDPSocket = link->GetUDPFD().value_or(-1);
|
||||
|
||||
#if defined(ANDROID)
|
||||
m_OutboundUDPSocket = link->GetUDPFD().value_or(-1);
|
||||
#endif
|
||||
_linkManager.AddLink(std::move(link), false);
|
||||
return true;
|
||||
}
|
||||
throw std::runtime_error{
|
||||
fmt::format("Failed to init AF_INET and AF_INET6 on port {}", m_OutboundPort)};
|
||||
}
|
||||
|
||||
const llarp::net::Platform&
|
||||
Router::Net() const
|
||||
{
|
||||
return *llarp::net::Platform::Default_ptr();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -84,6 +84,9 @@ namespace llarp
|
|||
return m_PathBuildLimiter;
|
||||
}
|
||||
|
||||
const llarp::net::Platform&
|
||||
Net() const override;
|
||||
|
||||
const LMQ_ptr&
|
||||
lmq() const override
|
||||
{
|
||||
|
@ -208,6 +211,9 @@ namespace llarp
|
|||
bool
|
||||
ShouldTestOtherRouters() const;
|
||||
|
||||
int
|
||||
OutboundUDPSocket() const override;
|
||||
|
||||
std::optional<SockAddr> _ourAddress;
|
||||
|
||||
EventLoop_ptr _loop;
|
||||
|
@ -227,7 +233,6 @@ namespace llarp
|
|||
bool
|
||||
Sign(Signature& sig, const llarp_buffer_t& buf) const override;
|
||||
|
||||
uint16_t m_OutboundPort = 0;
|
||||
/// how often do we resign our RC? milliseconds.
|
||||
// TODO: make configurable
|
||||
llarp_time_t rcRegenInterval = 1h;
|
||||
|
@ -363,7 +368,10 @@ namespace llarp
|
|||
bool
|
||||
HandleRecvLinkMessageBuffer(ILinkSession* from, const llarp_buffer_t& msg) override;
|
||||
|
||||
bool
|
||||
void
|
||||
InitInboundLinks();
|
||||
|
||||
void
|
||||
InitOutboundLinks();
|
||||
|
||||
bool
|
||||
|
@ -541,16 +549,8 @@ namespace llarp
|
|||
return m_Config;
|
||||
}
|
||||
|
||||
#if defined(ANDROID)
|
||||
int m_OutboundUDPSocket = -1;
|
||||
|
||||
int
|
||||
GetOutboundUDPSocket() const override
|
||||
{
|
||||
return m_OutboundUDPSocket;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::atomic<bool> _stopping;
|
||||
std::atomic<bool> _running;
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
|
||||
#include <oxenc/endian.h>
|
||||
|
||||
#include <llarp/router/abstractrouter.hpp>
|
||||
#include <llarp.hpp>
|
||||
|
||||
namespace llarp::vpn
|
||||
{
|
||||
struct in6_ifreq
|
||||
|
@ -290,7 +293,7 @@ namespace llarp::vpn
|
|||
DefaultRouteViaInterface(std::string ifname, int cmd, int flags)
|
||||
{
|
||||
int if_idx = if_nametoindex(ifname.c_str());
|
||||
const auto maybe = GetInterfaceAddr(ifname);
|
||||
const auto maybe = Net().GetInterfaceAddr(ifname);
|
||||
if (not maybe)
|
||||
throw std::runtime_error{"we dont have our own network interface?"};
|
||||
|
||||
|
@ -301,7 +304,7 @@ namespace llarp::vpn
|
|||
Route(cmd, flags, lower, gateway, GatewayMode::eLowerDefault, if_idx);
|
||||
Route(cmd, flags, upper, gateway, GatewayMode::eUpperDefault, if_idx);
|
||||
|
||||
if (const auto maybe6 = GetInterfaceIPv6Address(ifname))
|
||||
if (const auto maybe6 = Net().GetInterfaceIPv6Address(ifname))
|
||||
{
|
||||
const _inet_addr gateway6{*maybe6, 128};
|
||||
for (const std::string str : {"::", "4000::", "8000::", "c000::"})
|
||||
|
@ -320,7 +323,7 @@ namespace llarp::vpn
|
|||
int if_idx = if_nametoindex(ifname.c_str());
|
||||
if (range.IsV4())
|
||||
{
|
||||
const auto maybe = GetInterfaceAddr(ifname);
|
||||
const auto maybe = Net().GetInterfaceAddr(ifname);
|
||||
if (not maybe)
|
||||
throw std::runtime_error{"we dont have our own network interface?"};
|
||||
|
||||
|
@ -333,7 +336,7 @@ namespace llarp::vpn
|
|||
}
|
||||
else
|
||||
{
|
||||
const auto maybe = GetInterfaceIPv6Address(ifname);
|
||||
const auto maybe = Net().GetInterfaceIPv6Address(ifname);
|
||||
if (not maybe)
|
||||
throw std::runtime_error{"we dont have our own network interface?"};
|
||||
const _inet_addr gateway{*maybe, 128};
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
|
||||
namespace llarp::vpn
|
||||
{
|
||||
const llarp::net::Platform*
|
||||
IRouteManager::Net_ptr() const
|
||||
{
|
||||
return llarp::net::Platform::Default_ptr();
|
||||
}
|
||||
|
||||
std::shared_ptr<Platform>
|
||||
MakeNativePlatform(llarp::Context* ctx)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <windows.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <llarp/util/str.hpp>
|
||||
|
||||
namespace llarp::win32
|
||||
{
|
||||
namespace
|
||||
{
|
||||
inline std::string
|
||||
error_to_string(DWORD err)
|
||||
{
|
||||
std::array<CHAR, 512> buffer{};
|
||||
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, &err, 0, 0, buffer.data(), buffer.size(), nullptr);
|
||||
return std::string{buffer.data()};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
error(DWORD err, std::string msg)
|
||||
: std::runtime_error{fmt::format("{}: {}", msg, error_to_string(err))}
|
||||
{}
|
||||
};
|
||||
} // namespace llarp::win32
|
|
@ -70,22 +70,12 @@ namespace llarp
|
|||
.def(py::init<>())
|
||||
.def(
|
||||
"setOutboundLink",
|
||||
[](LinksConfig& self, std::string _interface, int family, uint16_t port) {
|
||||
LinksConfig::LinkInfo info;
|
||||
info.m_interface = std::move(_interface);
|
||||
info.addressFamily = family;
|
||||
info.port = port;
|
||||
self.m_OutboundLink = std::move(info);
|
||||
[](LinksConfig& self, std::string addr) {
|
||||
self.OutboundLinks.emplace_back(std::move(addr));
|
||||
})
|
||||
.def(
|
||||
"addInboundLink",
|
||||
[](LinksConfig& self, std::string _interface, int family, uint16_t port) {
|
||||
LinksConfig::LinkInfo info;
|
||||
info.m_interface = std::move(_interface);
|
||||
info.addressFamily = family;
|
||||
info.port = port;
|
||||
self.m_InboundLinks.push_back(info);
|
||||
});
|
||||
.def("addInboundLink", [](LinksConfig& self, std::string addr) {
|
||||
self.InboundListenAddrs.emplace_back(std::move(addr));
|
||||
});
|
||||
|
||||
py::class_<ApiConfig>(mod, "ApiConfig")
|
||||
.def(py::init<>())
|
||||
|
|
|
@ -16,11 +16,11 @@ Tier 1:
|
|||
|
||||
* [Linux](#linux-install)
|
||||
* [Android](#apk-install)
|
||||
* [Windows](#windows-install)
|
||||
* [MacOS](#mac-install)
|
||||
|
||||
Tier 2:
|
||||
|
||||
* [Windows](#windows-install)
|
||||
* [MacOS](#mac-install)
|
||||
* [FreeBSD](#freebsd-install)
|
||||
|
||||
Currently Unsupported Platforms: (maintainers welcome)
|
||||
|
|
|
@ -18,7 +18,8 @@ add_executable(testAll
|
|||
config/test_llarp_config_definition.cpp
|
||||
config/test_llarp_config_ini.cpp
|
||||
config/test_llarp_config_output.cpp
|
||||
crypto/test_llarp_crypto_types.cpp
|
||||
config/test_llarp_config_values.cpp
|
||||
crypto/test_llarp_crypto_types.cpp
|
||||
crypto/test_llarp_crypto.cpp
|
||||
crypto/test_llarp_key_manager.cpp
|
||||
dns/test_llarp_dns_dns.cpp
|
||||
|
@ -29,7 +30,6 @@ add_executable(testAll
|
|||
path/test_path.cpp
|
||||
peerstats/test_peer_db.cpp
|
||||
peerstats/test_peer_types.cpp
|
||||
regress/2020-06-08-key-backup-bug.cpp
|
||||
router/test_llarp_router_version.cpp
|
||||
routing/test_llarp_routing_transfer_traffic.cpp
|
||||
routing/test_llarp_routing_obtainexitmessage.cpp
|
||||
|
|
|
@ -0,0 +1,286 @@
|
|||
#include <llarp/config/config.hpp>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
#include "mocks/mock_context.hpp"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
struct UnitTestConfigGenParameters : public llarp::ConfigGenParameters
|
||||
{
|
||||
const mocks::Network* const _plat;
|
||||
UnitTestConfigGenParameters(const mocks::Network* plat)
|
||||
: llarp::ConfigGenParameters{}, _plat{plat}
|
||||
{}
|
||||
|
||||
const llarp::net::Platform*
|
||||
Net_ptr() const override
|
||||
{
|
||||
return _plat;
|
||||
}
|
||||
};
|
||||
|
||||
struct UnitTestConfig : public llarp::Config
|
||||
{
|
||||
const mocks::Network* const _plat;
|
||||
|
||||
explicit UnitTestConfig(const mocks::Network* plat) : llarp::Config{std::nullopt}, _plat{plat}
|
||||
{}
|
||||
|
||||
std::unique_ptr<llarp::ConfigGenParameters>
|
||||
MakeGenParams() const override
|
||||
{
|
||||
return std::make_unique<UnitTestConfigGenParameters>(_plat);
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<UnitTestConfig>
|
||||
make_config_for_test(const mocks::Network* env, std::string_view ini_str = "")
|
||||
{
|
||||
auto conf = std::make_shared<UnitTestConfig>(env);
|
||||
conf->LoadString(ini_str, true);
|
||||
conf->lokid.whitelistRouters = false;
|
||||
conf->bootstrap.seednode = true;
|
||||
conf->bootstrap.files.clear();
|
||||
return conf;
|
||||
}
|
||||
|
||||
std::shared_ptr<UnitTestConfig>
|
||||
make_config(mocks::Network env, std::string_view ini_str = "")
|
||||
{
|
||||
auto conf = std::make_shared<UnitTestConfig>(&env);
|
||||
conf->LoadString(ini_str, true);
|
||||
conf->lokid.whitelistRouters = false;
|
||||
conf->bootstrap.seednode = true;
|
||||
conf->bootstrap.files.clear();
|
||||
return conf;
|
||||
}
|
||||
|
||||
void
|
||||
run_config_test(mocks::Network env, std::string_view ini_str)
|
||||
{
|
||||
auto conf = make_config_for_test(&env, ini_str);
|
||||
const auto opts = env.Opts();
|
||||
auto context = std::make_shared<mocks::MockContext>(env);
|
||||
|
||||
context->Configure(conf);
|
||||
context->Setup(opts);
|
||||
int ib_links{};
|
||||
int ob_links{};
|
||||
|
||||
context->router->linkManager().ForEachInboundLink([&ib_links](auto) { ib_links++; });
|
||||
context->router->linkManager().ForEachOutboundLink([&ob_links](auto) { ob_links++; });
|
||||
REQUIRE(ib_links == 1);
|
||||
REQUIRE(ob_links == 1);
|
||||
if (context->Run(opts))
|
||||
throw std::runtime_error{"non zero return"};
|
||||
}
|
||||
|
||||
TEST_CASE("service node bind section on valid network", "[config]")
|
||||
{
|
||||
std::unordered_multimap<std::string, llarp::IPRange> env{
|
||||
{"mock0", llarp::IPRange::FromIPv4(1, 1, 1, 1, 32)},
|
||||
{"lo", llarp::IPRange::FromIPv4(127, 0, 0, 1, 8)},
|
||||
};
|
||||
|
||||
SECTION("mock network is sane")
|
||||
{
|
||||
mocks::Network mock_net{env};
|
||||
REQUIRE(mock_net.GetInterfaceAddr("mock0"sv, AF_INET6) == std::nullopt);
|
||||
auto maybe_addr = mock_net.GetInterfaceAddr("mock0"sv, AF_INET);
|
||||
REQUIRE(maybe_addr != std::nullopt);
|
||||
REQUIRE(maybe_addr->hostString() == "1.1.1.1");
|
||||
REQUIRE(not mock_net.IsBogon(*maybe_addr));
|
||||
}
|
||||
|
||||
SECTION("empty config")
|
||||
{
|
||||
std::string_view ini_str = "";
|
||||
REQUIRE_NOTHROW(run_config_test(env, ini_str));
|
||||
}
|
||||
|
||||
SECTION("explicit bind via ifname")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[bind]
|
||||
mock0=443
|
||||
)";
|
||||
run_config_test(env, ini_str);
|
||||
}
|
||||
SECTION("explicit bind via ip address")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[bind]
|
||||
inbound=1.1.1.1:443
|
||||
)";
|
||||
REQUIRE_NOTHROW(run_config_test(env, ini_str));
|
||||
}
|
||||
SECTION("explicit bind via ip address with old syntax")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[bind]
|
||||
1.1.1.1=443
|
||||
)";
|
||||
|
||||
REQUIRE_NOTHROW(run_config_test(env, ini_str));
|
||||
}
|
||||
SECTION("ip spoof fails")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[router]
|
||||
public-ip=8.8.8.8
|
||||
public-port=443
|
||||
[bind]
|
||||
inbound=1.1.1.1:443
|
||||
)";
|
||||
REQUIRE_THROWS(run_config_test(env, ini_str));
|
||||
}
|
||||
SECTION("explicit bind via ifname but fails from non existing ifname")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[bind]
|
||||
ligma0=443
|
||||
)";
|
||||
REQUIRE_THROWS(make_config(env, ini_str));
|
||||
}
|
||||
|
||||
SECTION("explicit bind via ifname but fails from using loopback")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[bind]
|
||||
lo=443
|
||||
)";
|
||||
REQUIRE_THROWS(make_config(env, ini_str));
|
||||
}
|
||||
|
||||
SECTION("explicit bind via explicit loopback")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[bind]
|
||||
inbound=127.0.0.1:443
|
||||
)";
|
||||
REQUIRE_THROWS(make_config(env, ini_str));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("service node bind section on nat network", "[config]")
|
||||
{
|
||||
std::unordered_multimap<std::string, llarp::IPRange> env{
|
||||
{"mock0", llarp::IPRange::FromIPv4(10, 1, 1, 1, 32)},
|
||||
{"lo", llarp::IPRange::FromIPv4(127, 0, 0, 1, 8)},
|
||||
};
|
||||
SECTION("no public ip set should fail")
|
||||
{
|
||||
std::string_view ini_str = "";
|
||||
REQUIRE_THROWS(run_config_test(env, ini_str));
|
||||
}
|
||||
|
||||
SECTION("public ip provided via inbound directive")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[router]
|
||||
public-ip=1.1.1.1
|
||||
public-port=443
|
||||
|
||||
[bind]
|
||||
inbound=10.1.1.1:443
|
||||
)";
|
||||
REQUIRE_NOTHROW(run_config_test(env, ini_str));
|
||||
}
|
||||
|
||||
SECTION("public ip provided with bind via ifname")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[router]
|
||||
public-ip=1.1.1.1
|
||||
public-port=443
|
||||
|
||||
[bind]
|
||||
mock0=443
|
||||
)";
|
||||
REQUIRE_NOTHROW(run_config_test(env, ini_str));
|
||||
}
|
||||
|
||||
SECTION("public ip provided bind via wildcard ip")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[router]
|
||||
public-ip=1.1.1.1
|
||||
public-port=443
|
||||
|
||||
[bind]
|
||||
inbound=0.0.0.0:443
|
||||
)";
|
||||
REQUIRE_THROWS(run_config_test(env, ini_str));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("service node bind section with multiple public ip", "[config]")
|
||||
{
|
||||
std::unordered_multimap<std::string, llarp::IPRange> env{
|
||||
{"mock0", llarp::IPRange::FromIPv4(1, 1, 1, 1, 32)},
|
||||
{"mock0", llarp::IPRange::FromIPv4(2, 1, 1, 1, 32)},
|
||||
{"lo", llarp::IPRange::FromIPv4(127, 0, 0, 1, 8)},
|
||||
};
|
||||
SECTION("empty config")
|
||||
{
|
||||
std::string_view ini_str = "";
|
||||
REQUIRE_NOTHROW(run_config_test(env, ini_str));
|
||||
}
|
||||
SECTION("with old style wildcard for inbound and no public ip")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[bind]
|
||||
0.0.0.0=443
|
||||
)";
|
||||
REQUIRE_THROWS(run_config_test(env, ini_str));
|
||||
}
|
||||
SECTION("with old style wildcard for outbound")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[bind]
|
||||
*=1443
|
||||
)";
|
||||
REQUIRE_NOTHROW(run_config_test(env, ini_str));
|
||||
}
|
||||
SECTION("with wildcard via inbound directive no public ip given, fails")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[bind]
|
||||
inbound=0.0.0.0:443
|
||||
)";
|
||||
|
||||
REQUIRE_THROWS(run_config_test(env, ini_str));
|
||||
}
|
||||
SECTION("with wildcard via inbound directive primary public ip given")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[router]
|
||||
public-ip=1.1.1.1
|
||||
public-port=443
|
||||
[bind]
|
||||
inbound=0.0.0.0:443
|
||||
)";
|
||||
|
||||
REQUIRE_THROWS(run_config_test(env, ini_str));
|
||||
}
|
||||
SECTION("with wildcard via inbound directive secondary public ip given")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[router]
|
||||
public-ip=2.1.1.1
|
||||
public-port=443
|
||||
[bind]
|
||||
inbound=0.0.0.0:443
|
||||
)";
|
||||
|
||||
REQUIRE_THROWS(run_config_test(env, ini_str));
|
||||
}
|
||||
SECTION("with bind via interface name")
|
||||
{
|
||||
std::string_view ini_str = R"(
|
||||
[bind]
|
||||
mock0=443
|
||||
)";
|
||||
REQUIRE_NOTHROW(run_config_test(env, ini_str));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
#include <llarp.hpp>
|
||||
|
||||
#include "mock_network.hpp"
|
||||
#include "mock_router.hpp"
|
||||
#include "mock_vpn.hpp"
|
||||
|
||||
namespace mocks
|
||||
{
|
||||
class MockContext : public llarp::Context
|
||||
{
|
||||
const Network& _net;
|
||||
|
||||
public:
|
||||
MockContext(const Network& net) : llarp::Context{}, _net{net}
|
||||
{
|
||||
loop = std::shared_ptr<llarp::EventLoop>{const_cast<Network*>(&_net), [](Network*) {}};
|
||||
}
|
||||
|
||||
std::shared_ptr<llarp::AbstractRouter>
|
||||
makeRouter(const std::shared_ptr<llarp::EventLoop>&) override
|
||||
{
|
||||
return std::static_pointer_cast<llarp::AbstractRouter>(
|
||||
std::make_shared<MockRouter>(_net, makeVPNPlatform()));
|
||||
}
|
||||
|
||||
std::shared_ptr<llarp::vpn::Platform>
|
||||
makeVPNPlatform() override
|
||||
{
|
||||
return std::static_pointer_cast<llarp::vpn::Platform>(std::make_shared<MockVPN>(_net));
|
||||
}
|
||||
|
||||
std::shared_ptr<llarp::NodeDB>
|
||||
makeNodeDB() override
|
||||
{
|
||||
return std::make_shared<llarp::NodeDB>();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mocks
|
|
@ -0,0 +1,192 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <llarp/net/net.hpp>
|
||||
#include <llarp/ev/ev_libuv.hpp>
|
||||
#include <oxenc/variant.h>
|
||||
|
||||
namespace mocks
|
||||
{
|
||||
class Network;
|
||||
|
||||
class MockUDPHandle : public llarp::UDPHandle
|
||||
{
|
||||
Network* const _net;
|
||||
|
||||
public:
|
||||
MockUDPHandle(Network* net, llarp::UDPHandle::ReceiveFunc recv)
|
||||
: llarp::UDPHandle{recv}, _net{net}
|
||||
{}
|
||||
|
||||
bool
|
||||
listen(const llarp::SockAddr& addr) override;
|
||||
|
||||
bool
|
||||
send(const llarp::SockAddr&, const llarp_buffer_t&) override
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
void
|
||||
close() override{};
|
||||
};
|
||||
|
||||
class Network : public llarp::net::Platform, public llarp::uv::Loop
|
||||
{
|
||||
std::unordered_multimap<std::string, llarp::IPRange> _network_interfaces;
|
||||
bool _snode;
|
||||
|
||||
const Platform* const m_Default{Platform::Default_ptr()};
|
||||
|
||||
public:
|
||||
Network(
|
||||
std::unordered_multimap<std::string, llarp::IPRange> network_interfaces, bool snode = true)
|
||||
: llarp::net::Platform{}
|
||||
, llarp::uv::Loop{1024}
|
||||
, _network_interfaces{std::move(network_interfaces)}
|
||||
, _snode{snode}
|
||||
{}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
m_EventLoopThreadID = std::this_thread::get_id();
|
||||
m_Impl->run<uvw::Loop::Mode::ONCE>();
|
||||
m_Impl->close();
|
||||
// reset the event loop for reuse
|
||||
m_Impl = uvw::Loop::create();
|
||||
};
|
||||
|
||||
llarp::RuntimeOptions
|
||||
Opts() const
|
||||
{
|
||||
return llarp::RuntimeOptions{false, false, _snode};
|
||||
}
|
||||
|
||||
std::shared_ptr<llarp::UDPHandle>
|
||||
make_udp(UDPReceiveFunc recv) override
|
||||
{
|
||||
return std::make_shared<MockUDPHandle>(this, recv);
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
GetBestNetIF(int af) const override
|
||||
{
|
||||
for (const auto& [k, range] : _network_interfaces)
|
||||
if (range.Family() == af and not range.BogonRange())
|
||||
return k;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
FindFreeTun() const override
|
||||
{
|
||||
return "mocktun0";
|
||||
}
|
||||
|
||||
std::optional<llarp::SockAddr>
|
||||
GetInterfaceAddr(std::string_view ifname, int af) const override
|
||||
{
|
||||
for (const auto& [name, range] : _network_interfaces)
|
||||
if (range.Family() == af and name == ifname)
|
||||
return llarp::SockAddr{range.addr};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool
|
||||
HasInterfaceAddress(llarp::net::ipaddr_t ip) const override
|
||||
{
|
||||
for (const auto& item : _network_interfaces)
|
||||
if (var::visit([range = item.second](auto&& ip) { return range.Contains(ToHost(ip)); }, ip))
|
||||
return true;
|
||||
// check for wildcard
|
||||
return IsWildcardAddress(ip);
|
||||
}
|
||||
|
||||
std::optional<llarp::SockAddr>
|
||||
AllInterfaces(llarp::SockAddr fallback) const override
|
||||
{
|
||||
return m_Default->AllInterfaces(fallback);
|
||||
}
|
||||
|
||||
llarp::SockAddr
|
||||
Wildcard(int af) const override
|
||||
{
|
||||
return m_Default->Wildcard(af);
|
||||
}
|
||||
|
||||
bool
|
||||
IsBogon(const llarp::SockAddr& addr) const override
|
||||
{
|
||||
return m_Default->IsBogon(addr);
|
||||
}
|
||||
bool
|
||||
IsLoopbackAddress(llarp::net::ipaddr_t ip) const override
|
||||
{
|
||||
return m_Default->IsLoopbackAddress(ip);
|
||||
}
|
||||
|
||||
bool
|
||||
IsWildcardAddress(llarp::net::ipaddr_t ip) const override
|
||||
{
|
||||
return m_Default->IsWildcardAddress(ip);
|
||||
}
|
||||
|
||||
std::optional<int>
|
||||
GetInterfaceIndex(llarp::net::ipaddr_t ip) const override
|
||||
{
|
||||
return m_Default->GetInterfaceIndex(ip);
|
||||
}
|
||||
|
||||
std::optional<llarp::IPRange>
|
||||
FindFreeRange() const override
|
||||
{
|
||||
auto ownsRange = [this](const auto& range) {
|
||||
for (const auto& [name, ownRange] : _network_interfaces)
|
||||
{
|
||||
if (ownRange * range)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
using namespace llarp;
|
||||
// generate possible ranges to in order of attempts
|
||||
std::list<IPRange> possibleRanges;
|
||||
for (byte_t oct = 16; oct < 32; ++oct)
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(172, oct, 0, 1, 16));
|
||||
}
|
||||
for (byte_t oct = 0; oct < 255; ++oct)
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(10, oct, 0, 1, 16));
|
||||
}
|
||||
for (byte_t oct = 0; oct < 255; ++oct)
|
||||
{
|
||||
possibleRanges.emplace_back(IPRange::FromIPv4(192, 168, oct, 1, 24));
|
||||
}
|
||||
// for each possible range pick the first one we don't own
|
||||
for (const auto& range : possibleRanges)
|
||||
{
|
||||
if (not ownsRange(range))
|
||||
return range;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string
|
||||
LoopbackInterfaceName() const override
|
||||
{
|
||||
for (const auto& [name, range] : _network_interfaces)
|
||||
if (IsLoopbackAddress(ToNet(range.addr)))
|
||||
return name;
|
||||
throw std::runtime_error{"no loopback interface?"};
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
MockUDPHandle::listen(const llarp::SockAddr& addr)
|
||||
{
|
||||
return _net->HasInterfaceAddress(addr.getIP());
|
||||
}
|
||||
|
||||
} // namespace mocks
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include <llarp/router/router.hpp>
|
||||
|
||||
#include "mock_network.hpp"
|
||||
|
||||
namespace mocks
|
||||
{
|
||||
class MockRouter : public llarp::Router
|
||||
{
|
||||
const Network& _net;
|
||||
|
||||
public:
|
||||
explicit MockRouter(const Network& net, std::shared_ptr<llarp::vpn::Platform> vpnPlatform)
|
||||
: llarp::
|
||||
Router{std::shared_ptr<llarp::EventLoop>{const_cast<Network*>(&net), [](Network*) {}}, vpnPlatform}
|
||||
, _net{net}
|
||||
{}
|
||||
|
||||
const llarp::net::Platform&
|
||||
Net() const override
|
||||
{
|
||||
return _net;
|
||||
};
|
||||
};
|
||||
} // namespace mocks
|
|
@ -0,0 +1,93 @@
|
|||
#pragma once
|
||||
#include <llarp/ev/vpn.hpp>
|
||||
#include "mock_network.hpp"
|
||||
|
||||
namespace mocks
|
||||
{
|
||||
class MockInterface : public llarp::vpn::NetworkInterface
|
||||
{
|
||||
int _pipes[2];
|
||||
|
||||
public:
|
||||
MockInterface(llarp::vpn::InterfaceInfo) : llarp::vpn::NetworkInterface{}
|
||||
{
|
||||
if (pipe(_pipes))
|
||||
throw std::runtime_error{strerror(errno)};
|
||||
}
|
||||
|
||||
virtual ~MockInterface()
|
||||
{
|
||||
close(_pipes[1]);
|
||||
}
|
||||
|
||||
int
|
||||
PollFD() const override
|
||||
{
|
||||
return _pipes[0];
|
||||
};
|
||||
|
||||
std::string
|
||||
IfName() const override
|
||||
{
|
||||
return "ligma";
|
||||
};
|
||||
|
||||
llarp::net::IPPacket
|
||||
ReadNextPacket() override
|
||||
{
|
||||
return llarp::net::IPPacket{};
|
||||
};
|
||||
|
||||
bool WritePacket(llarp::net::IPPacket) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class MockVPN : public llarp::vpn::Platform, public llarp::vpn::IRouteManager
|
||||
{
|
||||
const Network& _net;
|
||||
|
||||
public:
|
||||
MockVPN(const Network& net) : llarp::vpn::Platform{}, llarp::vpn::IRouteManager{}, _net{net}
|
||||
{}
|
||||
|
||||
virtual std::shared_ptr<llarp::vpn::NetworkInterface>
|
||||
ObtainInterface(llarp::vpn::InterfaceInfo info, llarp::AbstractRouter*) override
|
||||
{
|
||||
return std::make_shared<MockInterface>(info);
|
||||
};
|
||||
|
||||
const llarp::net::Platform*
|
||||
Net_ptr() const override
|
||||
{
|
||||
return &_net;
|
||||
};
|
||||
|
||||
void AddRoute(IPVariant_t, IPVariant_t) override{};
|
||||
|
||||
void DelRoute(IPVariant_t, IPVariant_t) override{};
|
||||
|
||||
void AddDefaultRouteViaInterface(std::string) override{};
|
||||
|
||||
void DelDefaultRouteViaInterface(std::string) override{};
|
||||
|
||||
void
|
||||
AddRouteViaInterface(llarp::vpn::NetworkInterface&, llarp::IPRange) override{};
|
||||
|
||||
void
|
||||
DelRouteViaInterface(llarp::vpn::NetworkInterface&, llarp::IPRange) override{};
|
||||
|
||||
std::vector<IPVariant_t> GetGatewaysNotOnInterface(std::string) override
|
||||
{
|
||||
return std::vector<IPVariant_t>{};
|
||||
};
|
||||
|
||||
/// get owned ip route manager for managing routing table
|
||||
virtual llarp::vpn::IRouteManager&
|
||||
RouteManager() override
|
||||
{
|
||||
return *this;
|
||||
};
|
||||
};
|
||||
} // namespace mocks
|
|
@ -1,77 +0,0 @@
|
|||
#include <llarp.hpp>
|
||||
#include <config/config.hpp>
|
||||
#include <router/abstractrouter.hpp>
|
||||
#include <service/context.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
llarp::RuntimeOptions opts = {false, false, false};
|
||||
|
||||
/// make a context with 1 endpoint that specifies a keyfile
|
||||
static std::shared_ptr<llarp::Context>
|
||||
make_context(std::optional<fs::path> keyfile)
|
||||
{
|
||||
auto conf = std::make_shared<llarp::Config>(fs::current_path());
|
||||
conf->Load(std::nullopt, opts.isSNode);
|
||||
conf->network.m_endpointType = "null";
|
||||
conf->network.m_keyfile = keyfile;
|
||||
conf->bootstrap.seednode = true;
|
||||
conf->api.m_enableRPCServer = false;
|
||||
|
||||
auto context = std::make_shared<llarp::Context>();
|
||||
REQUIRE_NOTHROW(context->Configure(std::move(conf)));
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/// test that we dont back up all keys when self.signed is missing or invalid as client
|
||||
TEST_CASE("key backup bug regression test", "[regress]")
|
||||
{
|
||||
// kill logging, this code is noisy
|
||||
// test 2 explicitly provided keyfiles, empty keyfile and no keyfile
|
||||
for (std::optional<fs::path> path : {std::optional<fs::path>{"regress-1.private"},
|
||||
std::optional<fs::path>{"regress-2.private"},
|
||||
std::optional<fs::path>{""},
|
||||
{std::nullopt}})
|
||||
{
|
||||
llarp::service::Address endpointAddress{};
|
||||
// try 10 start up and shut downs and see if our key changes or not
|
||||
for (size_t index = 0; index < 10; index++)
|
||||
{
|
||||
auto ctx = make_context(path);
|
||||
REQUIRE_NOTHROW(ctx->Setup(opts));
|
||||
ctx->CallSafe([ctx, index, &endpointAddress, &path]() {
|
||||
auto ep = ctx->router->hiddenServiceContext().GetDefault();
|
||||
REQUIRE(ep != nullptr);
|
||||
if (index == 0)
|
||||
{
|
||||
REQUIRE(endpointAddress.IsZero());
|
||||
// first iteration, we are getting our identity that we start with
|
||||
endpointAddress = ep->GetIdentity().pub.Addr();
|
||||
REQUIRE(not endpointAddress.IsZero());
|
||||
}
|
||||
else
|
||||
{
|
||||
REQUIRE(not endpointAddress.IsZero());
|
||||
if (path.has_value() and not path->empty())
|
||||
{
|
||||
// we have a keyfile provided
|
||||
// after the first iteration we expect the keys to stay the same
|
||||
REQUIRE(endpointAddress == ep->GetIdentity().pub.Addr());
|
||||
}
|
||||
else
|
||||
{
|
||||
// we want the keys to shift because no keyfile was provided
|
||||
REQUIRE(endpointAddress != ep->GetIdentity().pub.Addr());
|
||||
}
|
||||
}
|
||||
// close the router right away
|
||||
ctx->router->Die();
|
||||
});
|
||||
REQUIRE(ctx->Run({}) == 0);
|
||||
ctx.reset();
|
||||
}
|
||||
// remove keys if provied
|
||||
if (path.has_value() and not path->empty())
|
||||
fs::remove(*path);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue