From 4bf80833f49498c310877d532c92bde890cc7dc7 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 6 Oct 2022 14:50:05 -0300 Subject: [PATCH 1/8] Add InterfaceInfo formatter --- llarp/CMakeLists.txt | 1 + llarp/net/interface_info.cpp | 15 +++++++++++++++ llarp/net/interface_info.hpp | 8 ++++++++ 3 files changed, 24 insertions(+) create mode 100644 llarp/net/interface_info.cpp diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index a42c76bb1..2e3c558df 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -33,6 +33,7 @@ add_library(lokinet-platform # for networking ev/ev.cpp ev/libuv.cpp + net/interface_info.cpp net/ip.cpp net/ip_address.cpp net/ip_packet.cpp diff --git a/llarp/net/interface_info.cpp b/llarp/net/interface_info.cpp new file mode 100644 index 000000000..04490095b --- /dev/null +++ b/llarp/net/interface_info.cpp @@ -0,0 +1,15 @@ +#include "interface_info.hpp" + +namespace llarp::net +{ + std::string + InterfaceInfo::ToString() const + { + return fmt::format( + "{}[i={}; addrs={}; gw={}]", + name, + index, + fmt::join(addrs, ","), + gateway ? fmt::format("{}", *gateway) : "none"); + } +} // namespace llarp::net diff --git a/llarp/net/interface_info.hpp b/llarp/net/interface_info.hpp index c5d897264..a603b03bd 100644 --- a/llarp/net/interface_info.hpp +++ b/llarp/net/interface_info.hpp @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include #include "ip_range.hpp" namespace llarp::net @@ -17,5 +19,11 @@ namespace llarp::net std::vector addrs; /// a gateway we can use if it exists std::optional gateway; + + std::string + ToString() const; }; } // namespace llarp::net + +template <> +inline constexpr bool llarp::IsToStringFormattable = true; From d10c4b9d17895efe553ceeae5b83d93e9005ee08 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 6 Oct 2022 14:32:45 -0300 Subject: [PATCH 2/8] Add more logging around route poking conditions Log why we aren't doing anything if we aren't going to do anything. --- llarp/router/route_poker.cpp | 44 +++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/llarp/router/route_poker.cpp b/llarp/router/route_poker.cpp index df29a36b0..8b38b133a 100644 --- a/llarp/router/route_poker.cpp +++ b/llarp/router/route_poker.cpp @@ -156,7 +156,7 @@ namespace llarp next_gw = *gw_ptr; } - // update current gateway and apply state chnages as needed + // update current gateway and apply state changes as needed if (m_CurrentGateway != next_gw) { if (next_gw and m_CurrentGateway) @@ -172,7 +172,7 @@ namespace llarp m_CurrentGateway = next_gw; m_Router->Freeze(); } - else if (next_gw) + else // next_gw and not m_CurrentGateway { log::info(logcat, "default gateway found at {}", *next_gw); m_CurrentGateway = next_gw; @@ -197,24 +197,36 @@ namespace llarp { bool was_up = m_up; m_up = true; - if (IsEnabled() and m_CurrentGateway and not was_up) + if (not was_up) { - log::info(logcat, "RoutePoker coming up; poking routes"); + if (not IsEnabled()) + { + log::warning(logcat, "RoutePoker coming up, but route poking is disabled by config"); + } + else if (not m_CurrentGateway) + { + log::warning(logcat, "RokerPoker came up, but we don't know of a gateway!"); + } + else + { + log::info(logcat, "RoutePoker coming up; poking routes"); - vpn::IRouteManager& route = m_Router->GetVPNPlatform()->RouteManager(); + vpn::IRouteManager& route = m_Router->GetVPNPlatform()->RouteManager(); - // black hole all routes if enabled - if (m_Router->GetConfig()->network.m_BlackholeRoutes) - route.AddBlackhole(); + // black hole all routes if enabled + if (m_Router->GetConfig()->network.m_BlackholeRoutes) + route.AddBlackhole(); - // explicit route pokes for first hops - m_Router->ForEachPeer( - [this](auto session, auto) { AddRoute(session->GetRemoteEndpoint().getIPv4()); }, false); - // add default route - const auto ep = m_Router->hiddenServiceContext().GetDefault(); - if (auto* vpn = ep->GetVPNInterface()) - route.AddDefaultRouteViaInterface(*vpn); - log::info(logcat, "route poker up"); + // explicit route pokes for first hops + m_Router->ForEachPeer( + [this](auto session, auto) { AddRoute(session->GetRemoteEndpoint().getIPv4()); }, + false); + // add default route + const auto ep = m_Router->hiddenServiceContext().GetDefault(); + if (auto* vpn = ep->GetVPNInterface()) + route.AddDefaultRouteViaInterface(*vpn); + log::info(logcat, "route poker up"); + } } if (not was_up) SetDNSMode(true); From fe0f916a09fefc9d5e6f74b1e645831bb493b691 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 6 Oct 2022 15:45:42 -0300 Subject: [PATCH 3/8] DRY private range selection; add missing ranges DRY a chunk of repeated code for finding a free private range. Also fix it so that it will consider 10.255.0.1/16 and 192.168.255.1/24 (previously it would only check up to octet 254). --- llarp/net/ip_range.cpp | 21 +++++++++++++++++++++ llarp/net/ip_range.hpp | 9 ++++++++- llarp/net/posix.cpp | 30 +----------------------------- llarp/net/win32.cpp | 30 +----------------------------- 4 files changed, 31 insertions(+), 59 deletions(-) diff --git a/llarp/net/ip_range.cpp b/llarp/net/ip_range.cpp index ea3fe858e..eaee05fd4 100644 --- a/llarp/net/ip_range.cpp +++ b/llarp/net/ip_range.cpp @@ -101,4 +101,25 @@ namespace llarp return netmask_bits.ToString(); } + std::optional + IPRange::FindPrivateRange(const std::list& excluding) + { + auto good = [&excluding](const IPRange& range) -> bool { + for (const auto& ex : excluding) + if (ex * range) + return false; + return true; + }; + for (int oct = 16; oct <= 31; ++oct) + if (auto range = IPRange::FromIPv4(172, oct, 0, 1, 16); good(range)) + return range; + for (int oct = 0; oct <= 255; ++oct) + if (auto range = IPRange::FromIPv4(10, oct, 0, 1, 16); good(range)) + return range; + for (int oct = 0; oct <= 255; ++oct) + if (auto range = IPRange::FromIPv4(192, 168, oct, 1, 24); good(range)) + return range; + return std::nullopt; + } + } // namespace llarp diff --git a/llarp/net/ip_range.hpp b/llarp/net/ip_range.hpp index ca3ff25c4..9772793aa 100644 --- a/llarp/net/ip_range.hpp +++ b/llarp/net/ip_range.hpp @@ -1,10 +1,13 @@ #pragma once -#include + #include "ip.hpp" #include "net_bits.hpp" #include #include #include + +#include +#include #include namespace llarp @@ -144,6 +147,10 @@ namespace llarp bool BDecode(llarp_buffer_t* buf); + + /// Finds a free private use range not overlapping the given ranges. + static std::optional + FindPrivateRange(const std::list& excluding); }; template <> diff --git a/llarp/net/posix.cpp b/llarp/net/posix.cpp index 8d0cdfdde..44f7ccb64 100644 --- a/llarp/net/posix.cpp +++ b/llarp/net/posix.cpp @@ -90,35 +90,7 @@ namespace llarp::net } }); - 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 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; + return IPRange::FindPrivateRange(currentRanges); } std::optional GetInterfaceIndex(ipaddr_t) const override diff --git a/llarp/net/win32.cpp b/llarp/net/win32.cpp index 5db5382be..3a6de3448 100644 --- a/llarp/net/win32.cpp +++ b/llarp/net/win32.cpp @@ -151,35 +151,7 @@ namespace llarp::net } }); - 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 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; + return IPRange::FindPrivateRange(currentRanges); } std::string From e398b5bff88fd2ee4d3c89b84a5c3b664c9ff76f Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 6 Oct 2022 15:47:18 -0300 Subject: [PATCH 4/8] Fix interface enumeration on posix The last interface wouldn't be considered. --- llarp/net/posix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/net/posix.cpp b/llarp/net/posix.cpp index 44f7ccb64..b04398c0c 100644 --- a/llarp/net/posix.cpp +++ b/llarp/net/posix.cpp @@ -32,7 +32,7 @@ namespace llarp::net if (getifaddrs(&addrs)) throw std::runtime_error{fmt::format("getifaddrs(): {}", strerror(errno))}; - for (auto next = addrs; next and next->ifa_next; next = next->ifa_next) + for (auto next = addrs; next; next = next->ifa_next) visit(next); freeifaddrs(addrs); From 6f31d5108bc88a02004a7c68edc0e0fb9dc4d555 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 6 Oct 2022 16:03:49 -0300 Subject: [PATCH 5/8] Windows fix: iterate over IPv4/IPv6 interfaces separately If we get back an IPv6 address as the first gateway then we won't have the expected IPv4 gateway that the route poker needs to operate. This iterates through them separately so that we treat the IPv4 and IPv6 sides of an address as separate interfaces which should allow the route poker to find the one it wants (and just skip the IPv6 one). --- llarp/net/win32.cpp | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/llarp/net/win32.cpp b/llarp/net/win32.cpp index 3a6de3448..1bcaa86df 100644 --- a/llarp/net/win32.cpp +++ b/llarp/net/win32.cpp @@ -171,23 +171,27 @@ namespace llarp::net AllNetworkInterfaces() const override { std::vector all; - iter_adapters([&all](auto* a) { - auto& cur = all.emplace_back(); - cur.index = a->IfIndex; - cur.name = a->AdapterName; - for (auto* addr = a->FirstUnicastAddress; addr; addr = addr->Next) - { - SockAddr saddr{*addr->Address.lpSockaddr}; - cur.addrs.emplace_back( - saddr.asIPv6(), - ipaddr_netmask_bits(addr->OnLinkPrefixLength, addr->Address.lpSockaddr->sa_family)); - } - if (auto* addr = a->FirstGatewayAddress) - { - SockAddr gw{*addr->Address.lpSockaddr}; - cur.gateway = gw.getIP(); - } - }); + for (int af : {AF_INET, AF_INET6}) + iter_adapters( + [&all](auto* a) { + auto& cur = all.emplace_back(); + cur.index = a->IfIndex; + cur.name = a->AdapterName; + for (auto* addr = a->FirstUnicastAddress; addr; addr = addr->Next) + { + SockAddr saddr{*addr->Address.lpSockaddr}; + cur.addrs.emplace_back( + saddr.asIPv6(), + ipaddr_netmask_bits( + addr->OnLinkPrefixLength, addr->Address.lpSockaddr->sa_family)); + } + if (auto* addr = a->FirstGatewayAddress) + { + SockAddr gw{*addr->Address.lpSockaddr}; + cur.gateway = gw.getIP(); + } + }, + af); return all; } }; From 768e953522f97fa627bd63f5b82f577f2e641854 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 6 Oct 2022 16:23:55 -0300 Subject: [PATCH 6/8] De-prioritize some windivert logging We don't really need to log at info level for every windivert-intercepted incoming and outgoing packet. --- llarp/win32/windivert.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/llarp/win32/windivert.cpp b/llarp/win32/windivert.cpp index 7a04ece29..b359e1927 100644 --- a/llarp/win32/windivert.cpp +++ b/llarp/win32/windivert.cpp @@ -102,7 +102,7 @@ namespace llarp::win32 SetLastError(0); return std::nullopt; } - L::info(cat, "got packet of size {}B", sz); + L::trace(cat, "got packet of size {}B", sz); pkt.resize(sz); return Packet{std::move(pkt), std::move(addr)}; } @@ -112,7 +112,7 @@ namespace llarp::win32 { const auto& pkt = w_pkt.pkt; const auto* addr = &w_pkt.addr; - L::info(cat, "send dns packet of size {}B", pkt.size()); + L::trace(cat, "send dns packet of size {}B", pkt.size()); UINT sz{}; if (wd::send(m_Handle, pkt.data(), pkt.size(), &sz, addr)) return; @@ -151,7 +151,7 @@ namespace llarp::win32 throw std::runtime_error{"windivert thread is already running"}; auto read_loop = [this]() { - log::info(cat, "windivert read loop start"); + log::debug(cat, "windivert read loop start"); while (true) { // in the read loop, read packets until they stop coming in @@ -165,7 +165,7 @@ namespace llarp::win32 else // leave loop on read fail break; } - log::info(cat, "windivert read loop end"); + log::debug(cat, "windivert read loop end"); }; m_Runner = std::thread{std::move(read_loop)}; From 25d73d627ae9ea72a37ac8daf9d52c6478252bea Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 6 Oct 2022 18:45:56 -0300 Subject: [PATCH 7/8] Remake non-mac icon; regenerate during build for windows The non-mac icon was an old version with white foreground and a completely transparent background, but this looks bad (or invisible) depending on where you view it. This updates it based on the macos icon, but with a round white circle background instead of the macos "squircle" background. This also replaces the .ico file for the installer with one that we build during the win32 build rather than a pregenerated one. Bumps the gui as well to a version with the new icons in place. --- .drone.jsonnet | 3 +-- cmake/macos.cmake | 2 +- cmake/win32_installer_deps.cmake | 8 +++++- contrib/lokinet-mac.svg | 4 +-- contrib/lokinet.svg | 45 ++++++++++++++++++++------------ contrib/make-ico.sh | 28 ++++++++++++++++++++ gui | 2 +- 7 files changed, 69 insertions(+), 23 deletions(-) create mode 100755 contrib/make-ico.sh diff --git a/.drone.jsonnet b/.drone.jsonnet index c8b741f9c..203746cca 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -13,7 +13,6 @@ local default_deps_base = [ ]; local default_deps_nocxx = ['libsodium-dev'] + default_deps_base; // libsodium-dev needs to be >= 1.0.18 local default_deps = ['g++'] + default_deps_nocxx; -local default_windows_deps = ['mingw-w64', 'zip', 'nsis']; local docker_base = 'registry.oxen.rocks/lokinet-ci-'; local submodule_commands = [ @@ -147,7 +146,7 @@ local windows_cross_pipeline(name, 'echo "man-db man-db/auto-update boolean false" | debconf-set-selections', apt_get_quiet + ' update', apt_get_quiet + ' install -y eatmydata', - 'eatmydata ' + apt_get_quiet + ' install --no-install-recommends -y p7zip-full build-essential cmake git pkg-config ccache g++-mingw-w64-x86-64-posix nsis zip automake libtool', + 'eatmydata ' + apt_get_quiet + ' install --no-install-recommends -y p7zip-full build-essential cmake git pkg-config ccache g++-mingw-w64-x86-64-posix nsis zip icoutils automake libtool', 'update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix', 'update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix', 'JOBS=' + jobs + ' VERBOSE=1 ./contrib/windows.sh -DSTRIP_SYMBOLS=ON ' + diff --git a/cmake/macos.cmake b/cmake/macos.cmake index 1ca3aa0d9..a15a86e3d 100644 --- a/cmake/macos.cmake +++ b/cmake/macos.cmake @@ -127,7 +127,7 @@ endif() set(mac_icon "${PROJECT_BINARY_DIR}/lokinet.icns") add_custom_command(OUTPUT "${mac_icon}" COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet-mac.svg "${mac_icon}" - DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh) + DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet-mac.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh) add_custom_target(icon DEPENDS "${mac_icon}") if(BUILD_PACKAGE) diff --git a/cmake/win32_installer_deps.cmake b/cmake/win32_installer_deps.cmake index e937cabee..e0591466e 100644 --- a/cmake/win32_installer_deps.cmake +++ b/cmake/win32_installer_deps.cmake @@ -32,8 +32,14 @@ endif() set(BOOTSTRAP_FILE "${PROJECT_SOURCE_DIR}/contrib/bootstrap/mainnet.signed") install(FILES ${BOOTSTRAP_FILE} DESTINATION share COMPONENT lokinet RENAME bootstrap.signed) +set(win_ico "${PROJECT_BINARY_DIR}/lokinet.ico") +add_custom_command(OUTPUT "${win_ico}" + COMMAND ${PROJECT_SOURCE_DIR}/contrib/make-ico.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg "${win_ico}" + DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/make-ico.sh) +add_custom_target(icon ALL DEPENDS "${win_ico}") + set(CPACK_PACKAGE_INSTALL_DIRECTORY "Lokinet") -set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/win32-setup/lokinet.ico") +set(CPACK_NSIS_MUI_ICON "${PROJECT_BINARY_DIR}/lokinet.ico") set(CPACK_NSIS_DEFINES "RequestExecutionLevel admin") set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON) diff --git a/contrib/lokinet-mac.svg b/contrib/lokinet-mac.svg index ef9dd8b0e..10ddf0ca2 100644 --- a/contrib/lokinet-mac.svg +++ b/contrib/lokinet-mac.svg @@ -3,7 +3,7 @@ - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/contrib/make-ico.sh b/contrib/make-ico.sh new file mode 100755 index 000000000..9a0413a67 --- /dev/null +++ b/contrib/make-ico.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Invoked from cmake as make-ico.sh /path/to/icon.svg /path/to/output.ico +svg="$1" +out="$2" +outdir="$out.d" + +set -e + +sizes=(16 24 32 40 48 64 96 192 256) +outs="" + +mkdir -p "${outdir}" +for size in "${sizes[@]}"; do + outf="${outdir}/${size}x${size}.png" + if [ $size -lt 32 ]; then + # For 16x16 and 24x24 we crop the image to 3/4 of its regular size before resizing and make + # it all white (instead of transparent) which effectively zooms in on it a bit because if we + # resize the full icon it ends up a fuzzy mess, while the crop and resize lets us retain + # some detail of the logo. + convert -background white -resize 512x512 "$svg" -gravity Center -extent 320x320 -resize ${size}x${size} -strip "png32:$outf" + else + convert -background transparent -resize ${size}x${size} "$svg" -strip "png32:$outf" + fi + outs="-r $outf $outs" +done + +icotool -c -b 32 -o "$out" $outs diff --git a/gui b/gui index 37b1f015b..7b0f1aacd 160000 --- a/gui +++ b/gui @@ -1 +1 @@ -Subproject commit 37b1f015b73586c404971e6724721d4f1343ed50 +Subproject commit 7b0f1aacdf79b558adfc39dc9cccb7e348aeec03 From bc071231c83881c2d2ce31bd1a0aac31294acf99 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 6 Oct 2022 21:50:16 -0300 Subject: [PATCH 8/8] Add a net::ToString() to help stringify ipaddr_t Android, in particular, has problems with fmt's built-in variant handling for this type for some reason. --- llarp/net/interface_info.cpp | 2 +- llarp/net/net_int.cpp | 8 ++++++++ llarp/net/net_int.hpp | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/llarp/net/interface_info.cpp b/llarp/net/interface_info.cpp index 04490095b..370903b21 100644 --- a/llarp/net/interface_info.cpp +++ b/llarp/net/interface_info.cpp @@ -10,6 +10,6 @@ namespace llarp::net name, index, fmt::join(addrs, ","), - gateway ? fmt::format("{}", *gateway) : "none"); + gateway ? net::ToString(*gateway) : "none"); } } // namespace llarp::net diff --git a/llarp/net/net_int.cpp b/llarp/net/net_int.cpp index 1affa42e5..2628200ec 100644 --- a/llarp/net/net_int.cpp +++ b/llarp/net/net_int.cpp @@ -1,6 +1,7 @@ #include "net_int.hpp" #include "ip.hpp" #include +#include #include @@ -155,4 +156,11 @@ namespace llarp { return std::to_string(ntohs(n)); } + + std::string + net::ToString(const ipaddr_t& ipaddr) + { + return std::visit([](const auto& ip) { return ip.ToString(); }, ipaddr); + } + } // namespace llarp diff --git a/llarp/net/net_int.hpp b/llarp/net/net_int.hpp index d9894024d..e34f9b23b 100644 --- a/llarp/net/net_int.hpp +++ b/llarp/net/net_int.hpp @@ -230,6 +230,9 @@ namespace llarp using ipv6addr_t = n_uint128_t; using ipaddr_t = std::variant; + std::string + ToString(const ipaddr_t& ip); + huint16_t ToHost(port_t); huint32_t ToHost(ipv4addr_t); huint128_t ToHost(ipv6addr_t);