changeset for windows port

* wintun vpn platform for windows
* bundle config snippets into nsis installer for exit node, keyfile persisting, reduced hops mode.
* use wintun for vpn platform
* isolate all windows platform specific code into their own compilation units and libraries
* split up internal libraries into more specific components
* rename liblokinet.a target to liblokinet-amalgum.a to elimiate ambiguity with liblokinet.so
* DNS platform for win32
* rename llarp/ev/ev_libuv.{c,h}pp to llarp/ev/libuv.{c,h}pp as the old name was idiotic
* split up net platform into win32 and posix specific compilation units
* rename lokinet_init.c to easter_eggs.cpp as that is what they are for and it does not need to be a c compilation target
* add cmake option STRIP_SYMBOLS for seperating out debug symbols for windows builds
* intercept dns traffic on all interfaces on windows using windivert and feed it into lokinet
stable
jeff (codeaholic) 11 months ago committed by Jeff Becker
parent e981c9f899
commit 871c3e3281
Signed by: jeff
GPG Key ID: 025C02EE3A092F2D

@ -146,7 +146,7 @@ local windows_cross_pipeline(name,
'eatmydata ' + apt_get_quiet + ' install --no-install-recommends -y build-essential cmake git pkg-config ccache g++-mingw-w64-x86-64-posix nsis zip 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',
'VERBOSE=1 JOBS=' + jobs + ' ./contrib/windows.sh ' + ci_mirror_opts,
'JOBS=' + jobs + ' VERBOSE=1 ./contrib/windows.sh -DSTRIP_SYMBOLS=ON ' + ci_mirror_opts,
] + extra_cmds,
},
],

@ -61,6 +61,8 @@ option(WITH_HIVE "build simulation stubs" OFF)
option(BUILD_PACKAGE "builds extra components for making an installer (with 'make package')" OFF)
option(WITH_BOOTSTRAP "build lokinet-bootstrap tool" ${DEFAULT_WITH_BOOTSTRAP})
option(WITH_PEERSTATS "build with experimental peerstats db support" OFF)
option(STRIP_SYMBOLS "strip off all debug symbols into an external archive for all executables built" OFF)
include(cmake/enable_lto.cmake)
@ -81,6 +83,12 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()
set(debug OFF)
if(CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]")
set(debug ON)
add_definitions(-DLOKINET_DEBUG)
endif()
if(BUILD_STATIC_DEPS AND STATIC_LINK)
message(STATUS "we are building static deps so we won't build shared libs")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "")
@ -171,11 +179,18 @@ if(NOT TARGET sodium)
export(TARGETS sodium NAMESPACE sodium:: FILE sodium-exports.cmake)
endif()
if(NOT APPLE)
add_compile_options(-Wall -Wextra -Wno-unknown-pragmas -Wno-unused-function -Wno-deprecated-declarations -Werror=vla)
if(APPLE)
add_compile_options(-Wno-deprecated-declarations)
else()
add_compile_options(-Wall -Wextra -Wno-unknown-pragmas -Wno-unused-function -Werror=vla)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wno-unknown-warning-option)
endif()
if(debug)
add_compile_options(-Wdeprecated-declarations)
else()
add_compile_options(-Wno-deprecated-declarations)
endif()
endif()
if(XSAN)
@ -186,11 +201,6 @@ if(XSAN)
message(STATUS "Doing a ${XSAN} sanitizer build")
endif()
if(CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]")
add_definitions(-DLOKINET_DEBUG)
endif()
include(cmake/coverage.cmake)
# these vars are set by the cmake toolchain spec
@ -317,6 +327,10 @@ if(NOT TARGET uninstall)
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()
if(BUILD_PACKAGE)
include(cmake/installer.cmake)
if(BUILD_PACKAGE AND NOT APPLE)
include(cmake/installer.cmake)
endif()
if(TARGET package)
add_dependencies(package assemble_gui)
endif()

@ -2,6 +2,9 @@
include(CheckIPOSupported)
option(WITH_LTO "enable lto on compile time" ON)
if(WITH_LTO)
if(WIN32)
message(FATAL_ERROR "LTO not supported on win32 targets, please set -DWITH_LTO=OFF")
endif()
check_ipo_supported(RESULT IPO_ENABLED OUTPUT ipo_error)
if(IPO_ENABLED)
message(STATUS "LTO enabled")

@ -8,25 +8,30 @@ elseif(WIN32)
set(default_gui_target win32)
endif()
if(WIN32)
option(GUI_EXE "path to an externally built lokinet gui.exe" OFF)
endif()
option(BUILD_GUI "build electron gui from 'gui' submodule source" ${default_build_gui})
set(GUI_YARN_TARGET "${default_gui_target}" CACHE STRING "yarn target for building the GUI")
set(GUI_YARN_EXTRA_OPTS "" CACHE STRING "extra options to pass into the yarn build command")
if (BUILD_GUI)
message(STATUS "Building lokinet-gui")
# allow manually specifying yarn with -DYARN=
if(NOT YARN)
find_program(YARN NAMES yarn yarnpkg REQUIRED)
find_program(YARN NAMES yarnpkg yarn REQUIRED)
endif()
message(STATUS "Building lokinet-gui with yarn ${YARN}, target ${GUI_YARN_TARGET}")
set(wine_env)
if(WIN32)
set(wine_env USE_SYSTEM_7ZA=true DISPLAY= WINEDEBUG=-all "WINEPREFIX=${PROJECT_BINARY_DIR}/wineprefix")
endif()
add_custom_target(lokinet-gui
COMMAND ${YARN} install --frozen-lockfile &&
${wine_env} ${YARN} ${GUI_YARN_EXTRA_OPTS} ${GUI_YARN_TARGET}
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/gui")
if(NOT WIN32)
add_custom_target(lokinet-gui
COMMAND ${YARN} install --frozen-lockfile &&
${YARN} ${GUI_YARN_EXTRA_OPTS} ${GUI_YARN_TARGET}
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/gui")
endif()
if(APPLE)
add_custom_target(assemble_gui ALL
@ -38,14 +43,13 @@ if (BUILD_GUI)
COMMAND cp "${lokinet_app}/Contents/Resources/icon.icns" "${lokinet_app}/Contents/Helpers/Lokinet-GUI.app/Contents/Resources/icon.icns"
COMMAND cp "${PROJECT_SOURCE_DIR}/contrib/macos/InfoPlist.strings" "${lokinet_app}/Contents/Helpers/Lokinet-GUI.app/Contents/Resources/en.lproj/"
COMMAND /usr/libexec/PlistBuddy
-c "Delete :CFBundleDisplayName"
-c "Add :LSHasLocalizedDisplayName bool true"
-c "Add :CFBundleDevelopmentRegion string en"
-c "Set :CFBundleShortVersionString ${lokinet_VERSION}"
-c "Set :CFBundleVersion ${lokinet_VERSION}.${LOKINET_APPLE_BUILD}"
"${lokinet_app}/Contents/Helpers/Lokinet-GUI.app/Contents/Info.plist"
-c "Delete :CFBundleDisplayName"
-c "Add :LSHasLocalizedDisplayName bool true"
-c "Add :CFBundleDevelopmentRegion string en"
-c "Set :CFBundleShortVersionString ${lokinet_VERSION}"
-c "Set :CFBundleVersion ${lokinet_VERSION}.${LOKINET_APPLE_BUILD}"
"${lokinet_app}/Contents/Helpers/Lokinet-GUI.app/Contents/Info.plist"
)
elseif(WIN32)
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/gui")
option(GUI_ZIP_FILE "custom lokinet gui for windows from zip file" OFF)
@ -53,20 +57,28 @@ if (BUILD_GUI)
message(STATUS "using custom lokinet gui from ${GUI_ZIP_FILE}")
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf ${GUI_ZIP_FILE}
WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
add_custom_target("${PROJECT_BINARY_DIR}/gui/lokinet-gui.exe" COMMAND "true")
elseif(GUI_EXE)
message(STATUS "using custom lokinet gui executable: ${GUI_EXE}")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${GUI_EXE}" "${PROJECT_BINARY_DIR}/gui/lokinet-gui.exe")
add_custom_target("${PROJECT_BINARY_DIR}/gui/lokinet-gui.exe" COMMAND "true")
else()
add_custom_command(OUTPUT "${PROJECT_BINARY_DIR}/gui/lokinet-gui.exe"
DEPENDS lokinet lokinet-gui
# FIXME: we really shouldn't be building inside the source directory but this is npm...
COMMAND ${YARN} install --frozen-lockfile &&
USE_SYSTEM_7ZA=true DISPLAY= WINEDEBUG=-all WINEPREFIX="${PROJECT_BINARY_DIR}/wineprefix" ${YARN} ${GUI_YARN_EXTRA_OPTS} ${GUI_YARN_TARGET}
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${PROJECT_SOURCE_DIR}/gui/release/Lokinet-GUI_portable.exe"
"${PROJECT_BINARY_DIR}/gui/lokinet-gui.exe"
)
add_custom_target(assemble_gui ALL
DEPENDS ${PROJECT_BINARY_DIR}/gui/lokinet-gui.exe)
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/gui")
endif()
add_custom_target(assemble_gui ALL COMMAND "true" DEPENDS "${PROJECT_BINARY_DIR}/gui/lokinet-gui.exe")
else()
message(FATAL_ERROR "Building/bundling the GUI from this repository is not supported on this platform")
endif()
else()
message(STATUS "not building gui")
endif()
if(NOT TARGET assemble_gui)
add_custom_target(assemble_gui COMMAND "true")
endif()

@ -5,11 +5,42 @@ set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
if(WIN32)
include(cmake/win32_installer_deps.cmake)
install(FILES ${CMAKE_SOURCE_DIR}/contrib/configs/00-exit.ini DESTINATION share/conf.d COMPONENT exit_configs)
install(FILES ${CMAKE_SOURCE_DIR}/contrib/configs/00-keyfile.ini DESTINATION share/conf.d COMPONENT keyfile_configs)
install(FILES ${CMAKE_SOURCE_DIR}/contrib/configs/00-debug-log.ini DESTINATION share/conf.d COMPONENT debug_configs)
get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS)
list(REMOVE_ITEM CPACK_COMPONENTS_ALL "Unspecified" "lokinet" "gui" "exit_configs" "keyfile_configs" "debug_configs")
list(APPEND CPACK_COMPONENTS_ALL "lokinet" "gui" "exit_configs" "keyfile_configs" "debug_configs")
elseif(APPLE)
set(CPACK_GENERATOR DragNDrop;ZIP)
get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS)
list(REMOVE_ITEM CPACK_COMPONENTS_ALL "Unspecified")
endif()
# This must always be last!
include(CPack)
if(WIN32)
cpack_add_component(lokinet
DISPLAY_NAME "lokinet"
DESCRIPTION "core required lokinet files"
REQUIRED)
cpack_add_component(gui
DISPLAY_NAME "lokinet gui"
DESCRIPTION "electron based control panel for lokinet")
cpack_add_component(exit_configs
DISPLAY_NAME "auto-enable exit"
DESCRIPTION "automatically enable usage of exit.loki as an exit node\n"
DISABLED)
cpack_add_component(keyfile_configs
DISPLAY_NAME "persist address"
DESCRIPTION "persist .loki address across restarts of lokinet\nnot recommended when enabling exit nodes"
DISABLED)
cpack_add_component(debug_configs
DISPLAY_NAME "debug logging"
DESCRIPTION "enable debug spew log level by default"
DISABLED)
endif()

@ -1,32 +1,52 @@
if(NOT WIN32)
return()
endif()
if (NOT STATIC_LINK)
message(FATAL_ERROR "windows requires static builds (thanks balmer)")
endif()
enable_language(RC)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
if(NOT MSVC_VERSION)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-bad-function-cast>)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-cast-function-type>)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
# unlike unix where you get a *single* compiler ID string in .comment
# GNU ld sees fit to merge *all* the .ident sections in object files
# to .r[o]data section one after the other!
add_compile_options(-fno-ident -Wa,-mbig-obj)
link_libraries( -lws2_32 -lshlwapi -ldbghelp -luser32 -liphlpapi -lpsapi -luserenv)
# the minimum windows version, set to 6 rn because supporting older windows is hell
set(_winver 0x0600)
add_definitions(-DWINVER=${_winver} -D_WIN32_WINNT=${_winver})
endif()
option(WITH_WINDOWS_32 "build 32 bit windows" OFF)
# unlike unix where you get a *single* compiler ID string in .comment
# GNU ld sees fit to merge *all* the .ident sections in object files
# to .r[o]data section one after the other!
add_compile_options(-fno-ident -Wa,-mbig-obj)
# the minimum windows version, set to 6 rn because supporting older windows is hell
set(_winver 0x0600)
add_definitions(-D_WIN32_WINNT=${_winver})
if(EMBEDDED_CFG)
link_libatomic()
endif()
add_definitions(-DWIN32_LEAN_AND_MEAN -DWIN32)
set(WINTUN_VERSION 0.14.1 CACHE STRING "wintun version")
set(WINTUN_MIRROR https://www.wintun.net/builds
CACHE STRING "wintun mirror(s)")
set(WINTUN_SOURCE wintun-${WINTUN_VERSION}.zip)
set(WINTUN_HASH SHA256=07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51
CACHE STRING "wintun source hash")
if (NOT STATIC_LINK AND NOT MSVC)
message("must ship compiler runtime libraries with this build: libwinpthread-1.dll, libgcc_s_dw2-1.dll, and libstdc++-6.dll")
message("for release builds, turn on STATIC_LINK in cmake options")
endif()
set(WINDIVERT_VERSION 2.2.0-A CACHE STRING "windivert version")
set(WINDIVERT_MIRROR https://reqrypt.org/download
CACHE STRING "windivert mirror(s)")
set(WINDIVERT_SOURCE WinDivert-${WINDIVERT_VERSION}.zip)
set(WINDIVERT_HASH SHA256=2a7630aac0914746fbc565ac862fa096e3e54233883ac52d17c83107496b7a7f
CACHE STRING "windivert source hash")
set(WINTUN_URL ${WINTUN_MIRROR}/${WINTUN_SOURCE}
CACHE STRING "wintun download url")
set(WINDIVERT_URL ${WINDIVERT_MIRROR}/${WINDIVERT_SOURCE}
CACHE STRING "windivert download url")
message(STATUS "Downloading wintun from ${WINTUN_URL}")
file(DOWNLOAD ${WINTUN_URL} ${CMAKE_BINARY_DIR}/wintun.zip EXPECTED_HASH ${WINTUN_HASH})
message(STATUS "Downloading windivert from ${WINDIVERT_URL}")
file(DOWNLOAD ${WINDIVERT_URL} ${CMAKE_BINARY_DIR}/windivert.zip EXPECTED_HASH ${WINDIVERT_HASH})
execute_process(COMMAND ${CMAKE_COMMAND} -E tar x ${CMAKE_BINARY_DIR}/wintun.zip
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} -E tar x ${CMAKE_BINARY_DIR}/windivert.zip
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})

@ -1,11 +1,3 @@
set(TUNTAP_URL "https://build.openvpn.net/downloads/releases/latest/tap-windows-latest-stable.exe")
set(TUNTAP_EXE "${CMAKE_BINARY_DIR}/tuntap-install.exe")
set(BOOTSTRAP_FILE "${PROJECT_SOURCE_DIR}/contrib/bootstrap/mainnet.signed")
file(DOWNLOAD
${TUNTAP_URL}
${TUNTAP_EXE})
if(NOT BUILD_GUI)
if(NOT GUI_ZIP_URL)
set(GUI_ZIP_URL "https://oxen.rocks/oxen-io/lokinet-gui/dev/lokinet-windows-x64-20220331T180338Z-569f90ad8.zip")
@ -25,9 +17,19 @@ if(NOT BUILD_GUI)
message(FATAL_ERROR "Downloaded gui archive from ${GUI_ZIP_URL} does not contain gui/lokinet-gui.exe!")
endif()
endif()
install(DIRECTORY ${CMAKE_BINARY_DIR}/gui DESTINATION share COMPONENT gui)
install(PROGRAMS ${TUNTAP_EXE} DESTINATION bin COMPONENT tuntap)
if(WITH_WINDOWS_32)
install(FILES ${CMAKE_BINARY_DIR}/wintun/bin/x86/wintun.dll DESTINATION bin COMPONENT lokinet)
install(FILES ${CMAKE_BINARY_DIR}/WinDivert-${WINDIVERT_VERSION}/x86/WinDivert.sys DESTINATION lib COMPONENT lokinet)
install(FILES ${CMAKE_BINARY_DIR}/WinDivert-${WINDIVERT_VERSION}/x86/WinDivert.dll DESTINATION bin COMPONENT lokinet)
else()
install(FILES ${CMAKE_BINARY_DIR}/wintun/bin/amd64/wintun.dll DESTINATION bin COMPONENT lokinet)
install(FILES ${CMAKE_BINARY_DIR}/WinDivert-${WINDIVERT_VERSION}/x64/WinDivert64.sys DESTINATION lib COMPONENT lokinet)
install(FILES ${CMAKE_BINARY_DIR}/WinDivert-${WINDIVERT_VERSION}/x64/WinDivert.dll DESTINATION bin COMPONENT lokinet)
endif()
set(BOOTSTRAP_FILE "${PROJECT_SOURCE_DIR}/contrib/bootstrap/mainnet.signed")
install(FILES ${BOOTSTRAP_FILE} DESTINATION share COMPONENT lokinet RENAME bootstrap.signed)
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Lokinet")
@ -35,7 +37,6 @@ set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/win32-setup/lokinet.ico")
set(CPACK_NSIS_DEFINES "RequestExecutionLevel admin")
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
function(read_nsis_file filename outvar)
file(STRINGS "${filename}" _outvar)
list(TRANSFORM _outvar REPLACE "\\\\" "\\\\\\\\")
@ -51,9 +52,9 @@ read_nsis_file("${CMAKE_SOURCE_DIR}/win32-setup/extra_delete_icons.nsis" _extra_
set(CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS "${_extra_preinstall}")
set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${_extra_install}")
set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "${_extra_uninstall}")
set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "${_extra_uninstall}")
set(CPACK_NSIS_CREATE_ICONS_EXTRA "${_extra_create_icons}")
set(CPACK_NSIS_DELETE_ICONS_EXTRA "${_extra_delete_icons}")
set(CPACK_NSIS_MODIFY_PATH ON)
get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS)
list(REMOVE_ITEM CPACK_COMPONENTS_ALL "Unspecified")
set(CPACK_NSIS_COMPRESSOR "/SOLID lzma")

@ -34,6 +34,7 @@ for abi in $build_abis; do
-DBUILD_TESTING=OFF \
-DBUILD_LIBLOKINET=OFF \
-DWITH_TESTS=OFF \
-DWITH_BOOTSTRAP=OFF \
-DNATIVE_BUILD=OFF \
-DSTATIC_LINK=ON \
-DWITH_SYSTEMD=OFF \

@ -34,8 +34,11 @@ else
fi
mkdir -v "$base"
if [ -e build-windows ]; then
cp -av build-windows/lokinet-*.exe "$base"
if [ -e build/win32 ]; then
# save debug symbols
cp -av build/win32/daemon/debug-symbols.tar.xz "$base-debug-symbols.tar.xz"
# save installer
cp -av build/win32/*.exe "$base"
# zipit up yo
archive="$base.zip"
zip -r "$archive" "$base"
@ -77,6 +80,10 @@ $mkdirs
put $archive $upload_to
SFTP
if [ -e "$base-debug-symbols.tar.xz" ] ; then
sftp -i ssh_key -b - -o StrictHostKeyChecking=off drone@oxen.rocks <<<"put $base-debug-symbols.tar.xz $upload_to"
fi
set +o xtrace
echo -e "\n\n\n\n\e[32;1mUploaded to https://${upload_to}/${archive}\e[0m\n\n\n"

@ -0,0 +1,2 @@
[logging]
level=debug

@ -0,0 +1,5 @@
#
# "suggested" default exit node config
#
[network]
exit-node=exit.loki

@ -0,0 +1,5 @@
#
# persist .loki address in a private key file in the data dir
#
[network]
keyfile=lokinet-addr.privkey

@ -6,9 +6,8 @@
set -e
set +x
root="$(readlink -f $(dirname $0)/../)"
cd "$root"
./contrib/windows-configure.sh . build-windows "$@"
make package -j${JOBS:-$(nproc)} -C build-windows
mkdir -p $root/build/win32
$root/contrib/windows-configure.sh $root $root/build/win32 "$@"
make package -j${JOBS:-$(nproc)} -C $root/build/win32

@ -46,15 +46,27 @@ if(WITH_BOOTSTRAP)
endif()
endif()
# cmake interface library for bunch of cmake hacks to fix final link order
add_library(hax_and_shims_for_cmake INTERFACE)
if(WIN32)
target_link_libraries(hax_and_shims_for_cmake INTERFACE uvw oxenmq::oxenmq -lws2_32 -lshlwapi -ldbghelp -luser32 -liphlpapi -lpsapi -luserenv)
endif()
foreach(exe ${exetargets})
if(WIN32 AND NOT MSVC_VERSION)
if(WIN32)
target_sources(${exe} PRIVATE ${CMAKE_BINARY_DIR}/${exe}.rc)
target_compile_options(${exe} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
target_link_libraries(${exe} PRIVATE -static-libstdc++ -static-libgcc --static -Wl,--pic-executable,-e,mainCRTStartup,--subsystem,console:5.00)
target_link_libraries(${exe} PRIVATE ws2_32 iphlpapi)
elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
target_link_directories(${exe} PRIVATE /usr/local/lib)
endif()
target_link_libraries(${exe} PUBLIC liblokinet)
target_link_libraries(${exe} PUBLIC lokinet-amalgum hax_and_shims_for_cmake)
if(STRIP_SYMBOLS)
add_custom_command(TARGET ${exe}
POST_BUILD
COMMAND ${CMAKE_OBJCOPY} ARGS --only-keep-debug $<TARGET_FILE:${exe}> $<TARGET_FILE:${exe}>.debug
COMMAND ${CMAKE_STRIP} ARGS --strip-all $<TARGET_FILE:${exe}>)
endif()
target_include_directories(${exe} PUBLIC "${PROJECT_SOURCE_DIR}")
if(should_install)
if(APPLE)
@ -71,3 +83,9 @@ endforeach()
if(SETCAP)
install(CODE "execute_process(COMMAND ${SETCAP} cap_net_admin,cap_net_bind_service=+eip ${CMAKE_INSTALL_PREFIX}/bin/lokinet)")
endif()
if(STRIP_SYMBOLS)
add_custom_target(symbols ALL
COMMAND ${CMAKE_COMMAND} -E tar cJf ${CMAKE_CURRENT_BINARY_DIR}/debug-symbols.tar.xz $<TARGET_FILE:lokinet>.debug
DEPENDS lokinet)
endif()

@ -101,7 +101,7 @@ install_win32_daemon()
// Create the service
schService = CreateService(
schSCManager, // SCM database
"lokinet", // name of service
strdup("lokinet"), // name of service
"Lokinet for Windows", // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
@ -134,10 +134,10 @@ insert_description()
SC_HANDLE schSCManager;
SC_HANDLE schService;
SERVICE_DESCRIPTION sd;
LPTSTR szDesc =
LPTSTR szDesc = strdup(
"LokiNET is a free, open source, private, "
"decentralized, \"market based sybil resistant\" "
"and IP based onion routing network";
"and IP based onion routing network");
// Get a handle to the SCM database.
schSCManager = OpenSCManager(
NULL, // local computer
@ -270,7 +270,7 @@ run_main_context(std::optional<fs::path> confFile, const llarp::RuntimeOptions o
}
catch (std::exception& ex)
{
llarp::LogError("failed to start up lokinet: {}", ex.what());
llarp::LogError(fmt::format("failed to start up lokinet: {}", ex.what()));
exit_code.set_value(1);
return;
}
@ -367,7 +367,7 @@ main(int argc, char* argv[])
return lokinet_main(argc, argv);
#else
SERVICE_TABLE_ENTRY DispatchTable[] = {
{"lokinet", (LPSERVICE_MAIN_FUNCTION)win32_daemon_entry}, {NULL, NULL}};
{strdup("lokinet"), (LPSERVICE_MAIN_FUNCTION)win32_daemon_entry}, {NULL, NULL}};
if (lstrcmpi(argv[1], "--win32-daemon") == 0)
{
start_as_daemon = true;
@ -680,7 +680,7 @@ win32_daemon_entry(DWORD argc, LPTSTR* argv)
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
// SCM clobbers startup args, regenerate them here
argc = 2;
argv[1] = "c:/programdata/lokinet/lokinet.ini";
argv[1] = strdup("c:/programdata/lokinet/lokinet.ini");
argv[2] = nullptr;
lokinet_main(argc, argv);
}

@ -2,4 +2,4 @@ add_library(lokinet-android
SHARED
lokinet_config.cpp
lokinet_daemon.cpp)
target_link_libraries(lokinet-android liblokinet)
target_link_libraries(lokinet-android lokinet-amalgum)

@ -8,7 +8,7 @@ add_library(lokinet-util
util/fs.cpp
util/json.cpp
util/logging/buffer.cpp
util/lokinet_init.c
util/easter_eggs.cpp
util/mem.cpp
util/str.cpp
util/thread/queue_manager.cpp
@ -32,12 +32,11 @@ add_library(lokinet-platform
STATIC
# for networking
ev/ev.cpp
ev/ev_libuv.cpp
ev/libuv.cpp
net/ip.cpp
net/ip_address.cpp
net/ip_packet.cpp
net/ip_range.cpp
net/net.cpp
net/net_int.cpp
net/sock_addr.cpp
vpn/packet_router.cpp
@ -58,34 +57,66 @@ endif()
if (WIN32)
target_sources(lokinet-platform PRIVATE
win32/win32_inet.c
win32/win32_intrnl.c)
target_link_libraries(lokinet-platform PUBLIC iphlpapi)
net/win32.cpp
win32/exec.cpp)
add_library(lokinet-win32 STATIC
win32/dll.cpp
win32/exception.cpp)
add_library(lokinet-wintun STATIC
win32/wintun.cpp)
add_library(lokinet-windivert STATIC
win32/windivert.cpp)
# wintun and windivert are privated linked by lokinet-platform
# this is so their details do not leak out to deps of lokinet-platform
# wintun and windivert still need things from lokinet-platform
target_compile_options(lokinet-wintun PUBLIC -I${CMAKE_BINARY_DIR}/wintun/include/)
target_compile_options(lokinet-windivert PUBLIC -I${CMAKE_BINARY_DIR}/WinDivert-${WINDIVERT_VERSION}/include/)
target_include_directories(lokinet-windivert PUBLIC ${PROJECT_SOURCE_DIR})
target_link_libraries(lokinet-wintun PUBLIC lokinet-platform lokinet-util lokinet-config)
target_link_libraries(lokinet-win32 PUBLIC lokinet-util)
target_link_libraries(lokinet-windivert PUBLIC oxen-logging)
target_link_libraries(lokinet-windivert PRIVATE lokinet-win32)
target_link_libraries(lokinet-platform PRIVATE lokinet-win32 lokinet-wintun lokinet-windivert)
else()
target_sources(lokinet-platform PRIVATE
net/posix.cpp)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
target_include_directories(lokinet-platform SYSTEM PUBLIC /usr/local/include)
endif()
add_library(liblokinet
add_library(lokinet-dns
STATIC
config/config.cpp
config/definition.cpp
config/ini.cpp
config/key_manager.cpp
dns/message.cpp
dns/name.cpp
dns/multi_platform.cpp
dns/nm_platform.cpp
dns/sd_platform.cpp
dns/platform.cpp
dns/question.cpp
dns/rr.cpp
dns/serialize.cpp
dns/server.cpp
dns/srv_data.cpp
dns/srv_data.cpp)
if(WITH_SYSTEMD)
target_sources(lokinet-dns PRIVATE dns/nm_platform.cpp dns/sd_platform.cpp)
endif()
target_link_libraries(lokinet-dns PUBLIC lokinet-platform uvw)
target_link_libraries(lokinet-dns PRIVATE libunbound lokinet-config)
add_library(lokinet-config
STATIC
config/config.cpp
config/definition.cpp
config/ini.cpp
config/key_manager.cpp)
target_link_libraries(lokinet-config PUBLIC lokinet-dns lokinet-platform oxenmq::oxenmq)
add_library(lokinet-amalgum
STATIC
consensus/table.cpp
consensus/reachability_testing.cpp
@ -115,7 +146,7 @@ add_library(liblokinet
dht/taglookup.cpp
endpoint_base.cpp
exit/context.cpp
exit/endpoint.cpp
exit/exit_messages.cpp
@ -170,7 +201,7 @@ add_library(liblokinet
router/rc_gossiper.cpp
router/router.cpp
router/route_poker.cpp
routing/dht_message.cpp
routing/message_parser.cpp
routing/path_confirm_message.cpp
@ -204,42 +235,42 @@ add_library(liblokinet
service/tag.cpp
)
if(WITH_PEERSTATS_BACKEND)
target_compile_definitions(liblokinet PRIVATE -DLOKINET_PEERSTATS_BACKEND)
target_link_libraries(liblokinet PUBLIC sqlite_orm)
endif()
set_target_properties(liblokinet PROPERTIES OUTPUT_NAME lokinet)
enable_lto(lokinet-util lokinet-platform liblokinet)
if(TRACY_ROOT)
target_sources(liblokinet PRIVATE ${TRACY_ROOT}/TracyClient.cpp)
if(WITH_PEERSTATS_BACKEND)
target_compile_definitions(lokinet-amalgum PRIVATE -DLOKINET_PEERSTATS_BACKEND)
target_link_libraries(lokinet-amalgum PUBLIC sqlite_orm)
endif()
if(WITH_HIVE)
target_sources(liblokinet PRIVATE
target_sources(lokinet-amalgum PRIVATE
tooling/router_hive.cpp
tooling/hive_router.cpp
tooling/hive_context.cpp
)
endif()
target_link_libraries(liblokinet PUBLIC
# TODO: make libunbound hidden behind a feature flag like sqlite for embedded lokinet
target_link_libraries(lokinet-amalgum PRIVATE libunbound)
target_link_libraries(lokinet-amalgum PUBLIC
cxxopts
oxenc::oxenc
lokinet-platform
lokinet-config
lokinet-dns
lokinet-util
lokinet-cryptography
ngtcp2_static
oxenmq::oxenmq)
target_link_libraries(liblokinet PRIVATE libunbound)
enable_lto(lokinet-util lokinet-platform lokinet-dns lokinet-config lokinet-amalgum)
pkg_check_modules(CRYPT libcrypt IMPORTED_TARGET)
if(CRYPT_FOUND AND NOT CMAKE_CROSSCOMPILING)
add_definitions(-DHAVE_CRYPT)
add_library(libcrypt INTERFACE)
target_link_libraries(libcrypt INTERFACE PkgConfig::CRYPT)
target_link_libraries(liblokinet PRIVATE libcrypt)
target_link_libraries(lokinet-amalgum PRIVATE libcrypt)
message(STATUS "using libcrypt ${CRYPT_VERSION}")
endif()
@ -247,7 +278,7 @@ endif()
if(BUILD_LIBLOKINET)
include(GNUInstallDirs)
add_library(lokinet-shared SHARED lokinet_shared.cpp)
target_link_libraries(lokinet-shared PUBLIC liblokinet)
target_link_libraries(lokinet-shared PUBLIC lokinet-amalgum)
if(WIN32)
set(CMAKE_SHARED_LIBRARY_PREFIX_CXX "")
endif()

@ -18,12 +18,9 @@ target_sources(lokinet-platform PRIVATE vpn_platform.cpp vpn_interface.cpp route
add_executable(lokinet-extension MACOSX_BUNDLE
PacketTunnelProvider.m
DNSTrampoline.m
)
)
enable_lto(lokinet-extension)
target_link_libraries(lokinet-extension PRIVATE
liblokinet
${COREFOUNDATION}
${NETEXT})
# -fobjc-arc enables automatic reference counting for objective-C code
# -e _NSExtensionMain because the appex has that instead of a `main` function entry point, of course.
@ -43,6 +40,11 @@ else()
set(product_type com.apple.product-type.app-extension)
endif()
target_link_libraries(lokinet-extension PRIVATE
lokinet-amalgum
${COREFOUNDATION}
${NETEXT})
set_target_properties(lokinet-extension PROPERTIES
BUNDLE TRUE
BUNDLE_EXTENSION ${bundle_ext}

@ -1,7 +1,7 @@
#pragma once
#include <llarp.hpp>
#include <llarp/ev/vpn.hpp>
#include <llarp/vpn/platform.hpp>
#include <llarp/util/thread/queue.hpp>
#include <memory>

@ -140,14 +140,14 @@ namespace llarp
"this setting specifies the public IP at which this router is reachable. When",
"provided the public-port option must also be specified.",
},
[this](std::string arg) {
[this, net = params.Net_ptr()](std::string arg) {
if (arg.empty())
return;
nuint32_t addr{};
if (not addr.FromString(arg))
throw std::invalid_argument{fmt::format("{} is not a valid IPv4 address", arg)};
if (IsIPv4Bogon(addr))
if (net->IsBogonIP(addr))
throw std::invalid_argument{
fmt::format("{} is not a publicly routable ip address", addr)};
@ -648,6 +648,7 @@ namespace llarp
throw std::invalid_argument{
fmt::format("[network]:ip6-range invalid value: '{}'", arg)};
});
// TODO: could be useful for snodes in the future, but currently only implemented for clients:
conf.defineOption<std::string>(
"network",
@ -813,6 +814,30 @@ namespace llarp
}
});
conf.defineOption<bool>(
"dns",
"l3-intercept",
Default{
platform::is_windows or platform::is_android
or (platform::is_macos and not platform::is_apple_sysex)},
Comment{"Intercept all dns traffic (udp/53) going into our lokinet network interface "
"instead of binding a local udp socket"},
AssignmentAcceptor(m_raw_dns));
conf.defineOption<std::string>(
"dns",
"query-bind",
#ifdef __APPLE__
Default{"127.0.0.1:1253"},
#endif
#ifdef _WIN32
Default{"0.0.0.0:0"},
#endif
Comment{
"Address to bind to for sending upstream DNS requests.",
},
[this](std::string arg) { m_QueryBind = SockAddr{arg}; });
conf.defineOption<std::string>(
"dns",
"bind",

@ -155,9 +155,12 @@ namespace llarp
struct DnsConfig
{
bool m_raw_dns;
std::vector<SockAddr> m_bind;
std::vector<SockAddr> m_upstreamDNS;
std::vector<fs::path> m_hostfiles;
std::optional<SockAddr> m_QueryBind;
std::unordered_multimap<std::string, std::string> m_ExtraOpts;
void

@ -0,0 +1,7 @@
#pragma once
namespace llarp::constants
{
constexpr auto udp_header_bytes = 8;
constexpr auto ip_header_min_bytes = 20;
} // namespace llarp::constants

@ -11,8 +11,9 @@ namespace llarp::platform
false
#endif
;
/// we have systemd ?
inline constexpr bool has_systemd =
/// building with systemd enabled ?
inline constexpr bool with_systemd =
#ifdef WITH_SYSTEMD
true
#else
@ -47,6 +48,15 @@ namespace llarp::platform
#endif
;
/// are we building as an apple system extension
inline constexpr bool is_apple_sysex =
#ifdef MACOS_SYSTEM_EXTENSION
true
#else
false
#endif
;
/// are we an android platform ?
inline constexpr bool is_android =
#ifdef ANDROID
@ -65,9 +75,26 @@ namespace llarp::platform
#endif
;
/// are we running with pybind simulation mode enabled?
inline constexpr bool is_simulation =
#ifdef LOKINET_HIVE
true
#else
false
#endif
;
/// do we have systemd support ?
// on cross compiles sometimes weird permutations of target and host make this value not correct,
// this ensures it always is
inline constexpr bool has_systemd = is_linux and with_systemd and not(is_android or is_windows);
/// are we using macos ?
inline constexpr bool is_macos = is_apple and not is_iphone;
/// are we a mobile phone ?
inline constexpr bool is_mobile = is_android or is_iphone;
/// does this platform support native ipv6 ?
// TODO: make windows support ipv6
inline constexpr bool supports_ipv6 = not is_windows;
} // namespace llarp::platform

@ -1,22 +1 @@
#pragma once
#include "platform.hpp"
#include <vector>
namespace llarp::dns
{
/// a collection of dns platforms that are tried in order when setting dns
class Multi_Platform : public I_Platform
{
std::vector<std::unique_ptr<I_Platform>> m_Impls;
public:
/// add a platform to be owned
void
add_impl(std::unique_ptr<I_Platform> impl);
/// try all owned platforms to set the resolver, throws if none of them work
void
set_resolver(std::string ifname, llarp::SockAddr dns, bool global) override;
};
} // namespace llarp::dns

@ -13,7 +13,7 @@ using namespace std::literals;
namespace llarp::dns::nm
{
void
Platform::set_resolver(std::string, llarp::SockAddr, bool)
Platform::set_resolver(unsigned int, llarp::SockAddr, bool)
{
// todo: implement me eventually
}

@ -17,7 +17,7 @@ namespace llarp::dns
virtual ~Platform() = default;
void
set_resolver(std::string ifname, llarp::SockAddr dns, bool global) override;
set_resolver(unsigned int index, llarp::SockAddr dns, bool global) override;
};
}; // namespace nm
using NM_Platform_t = std::conditional_t<false, nm::Platform, Null_Platform>;

@ -1,14 +1 @@
#pragma once
#include "platform.hpp"
namespace llarp::dns
{
/// a dns platform does silently does nothing, successfully
class Null_Platform : public I_Platform
{
public:
void
set_resolver(std::string, llarp::SockAddr, bool) override
{}
};
} // namespace llarp::dns

@ -1,4 +1,4 @@
#include "multi_platform.hpp"
#include "platform.hpp"
namespace llarp::dns
{
@ -9,14 +9,14 @@ namespace llarp::dns
}
void
Multi_Platform::set_resolver(std::string ifname, llarp::SockAddr dns, bool global)
Multi_Platform::set_resolver(unsigned int index, llarp::SockAddr dns, bool global)
{
size_t fails{0};
for (const auto& ptr : m_Impls)
{
try
{
ptr->set_resolver(ifname, dns, global);
ptr->set_resolver(index, dns, global);
}
catch (std::exception& ex)
{

@ -3,9 +3,12 @@
#include <memory>
#include <llarp/net/sock_addr.hpp>
#include <llarp/util/logging.hpp>
#include <stdexcept>
#ifndef _WIN32
#include <net/if.h>
#endif
namespace llarp::dns
{
/// sets dns settings in a platform dependant way
@ -18,13 +21,39 @@ namespace llarp::dns
/// throws if unsupported or fails.
///
///
/// \param if_name -- the interface name to which we add the DNS servers, e.g. lokitun0.
/// Typically tun_endpoint.GetIfName().
/// \param if_index -- the interface index to which we add the DNS servers, this can be gotten
/// from the interface name e.g. lokitun0 (Typically tun_endpoint.GetIfName().) and then put
/// through if_nametoindex().
/// \param dns -- the listening address of the lokinet DNS server
/// \param global -- whether to set up lokinet for all DNS queries (true) or just .loki & .snode
/// addresses (false).
virtual void
set_resolver(std::string if_name, llarp::SockAddr dns, bool global) = 0;
set_resolver(unsigned int if_index, llarp::SockAddr dns, bool global) = 0;
};
/// a dns platform does silently does nothing, successfully
class Null_Platform : public I_Platform
{
public:
~Null_Platform() override = default;
void
set_resolver(unsigned int, llarp::SockAddr, bool) override
{}
};
/// a collection of dns platforms that are tried in order when setting dns
class Multi_Platform : public I_Platform
{
std::vector<std::unique_ptr<I_Platform>> m_Impls;
public:
~Multi_Platform() override = default;
/// add a platform to be owned
void
add_impl(std::unique_ptr<I_Platform> impl);
/// try all owned platforms to set the resolver, throws if none of them work
void
set_resolver(unsigned int if_index, llarp::SockAddr dns, bool global) override;
};
} // namespace llarp::dns

@ -13,14 +13,8 @@ using namespace std::literals;
namespace llarp::dns::sd
{
void
Platform::set_resolver(std::string ifname, llarp::SockAddr dns, bool global)
Platform::set_resolver(unsigned int if_ndx, llarp::SockAddr dns, bool global)
{
unsigned int if_ndx = if_nametoindex(ifname.c_str());
if (if_ndx == 0)
{
throw std::runtime_error{"No such interface '" + ifname + "'"};
}
linux::DBUS _dbus{
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",

@ -16,7 +16,7 @@ namespace llarp::dns
virtual ~Platform() = default;
void
set_resolver(std::string ifname, llarp::SockAddr dns, bool global) override;
set_resolver(unsigned int if_index, llarp::SockAddr dns, bool global) override;
};
} // namespace sd
using SD_Platform_t =

@ -9,9 +9,9 @@
#include <unbound.h>
#include <uvw.hpp>
#include "multi_platform.hpp"
#include "sd_platform.hpp"
#include "nm_platform.hpp"
#include "win32_platform.hpp"
namespace llarp::dns
{
@ -37,7 +37,7 @@ namespace llarp::dns
m_udp = loop->make_udp([&](auto&, SockAddr src, llarp::OwnedBuffer buf) {
if (src == m_LocalAddr)
return;
if (not m_DNS.MaybeHandlePacket(weak_from_this(), m_LocalAddr, src, std::move(buf)))
if (not m_DNS.MaybeHandlePacket(shared_from_this(), m_LocalAddr, src, std::move(buf)))
{
LogWarn("did not handle dns packet from ", src, " to ", m_LocalAddr);
}
@ -83,7 +83,7 @@ namespace llarp::dns
class Query : public QueryJob_Base
{
std::weak_ptr<Resolver> parent;
std::weak_ptr<PacketSource_Base> src;
std::shared_ptr<PacketSource_Base> src;
SockAddr resolverAddr;
SockAddr askerAddr;
@ -91,7 +91,7 @@ namespace llarp::dns
explicit Query(
std::weak_ptr<Resolver> parent_,
Message query,
std::weak_ptr<PacketSource_Base> pktsrc,
std::shared_ptr<PacketSource_Base> pktsrc,
SockAddr toaddr,
SockAddr fromaddr)
: QueryJob_Base{std::move(query)}
@ -118,6 +118,8 @@ namespace llarp::dns
std::shared_ptr<uvw::PollHandle> m_Poller;
#endif
std::optional<SockAddr> m_LocalAddr;
struct ub_result_deleter
{
void
@ -127,6 +129,12 @@ namespace llarp::dns
}
};
const net::Platform*
Net_ptr() const
{
return m_Loop.lock()->Net_ptr();
}
static void
Callback(void* data, int err, ub_result* _result)
{
@ -186,6 +194,12 @@ namespace llarp::dns
return "unbound";
}
virtual std::optional<SockAddr>
GetLocalAddr() const override
{
return m_LocalAddr;
}
void
Up(const llarp::DnsConfig& conf)
{
@ -220,23 +234,39 @@ namespace llarp::dns
throw std::runtime_error{
fmt::format("cannot use {} as upstream dns: {}", str, ub_strerror(err))};
}
#ifdef __APPLE__
// On Apple, we configure a localhost resolver to trampoline requests through the tunnel
// to the actual upstream (because the network extension itself cannot route through the