mirror of https://github.com/oxen-io/lokinet
Merge pull request #1942 from jagerman/macos-sysex
macOS system extension
This commit is contained in:
commit
13c71c3626
|
@ -260,6 +260,7 @@ local mac_builder(name,
|
|||
cmake_extra='',
|
||||
extra_cmds=[],
|
||||
jobs=6,
|
||||
codesign='-DCODESIGN=OFF',
|
||||
allow_fail=false) = {
|
||||
kind: 'pipeline',
|
||||
type: 'exec',
|
||||
|
@ -276,7 +277,7 @@ local mac_builder(name,
|
|||
// basic system headers. WTF apple:
|
||||
'export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"',
|
||||
'ulimit -n 1024', // because macos sets ulimit to 256 for some reason yeah idk
|
||||
'./contrib/mac.sh ' + ci_mirror_opts,
|
||||
'./contrib/mac.sh ' + ci_mirror_opts + ' ' + codesign,
|
||||
] + extra_cmds,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -36,3 +36,6 @@
|
|||
[submodule "external/oxen-logging"]
|
||||
path = external/oxen-logging
|
||||
url = https://github.com/oxen-io/oxen-logging.git
|
||||
[submodule "gui"]
|
||||
path = gui
|
||||
url = https://github.com/oxen-io/lokinet-gui.git
|
||||
|
|
|
@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.10) # bionic's cmake version
|
|||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# Has to be set before `project()`, and ignored on non-macos:
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12 CACHE STRING "macOS deployment target (Apple clang only)")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "macOS deployment target (Apple clang only)")
|
||||
|
||||
option(BUILD_DAEMON "build lokinet daemon and associated utils" ON)
|
||||
|
||||
|
@ -32,7 +32,7 @@ project(lokinet
|
|||
if(APPLE)
|
||||
# Apple build number: must be incremented to submit a new build for the same lokinet version,
|
||||
# should be reset to 0 when the lokinet version increments.
|
||||
set(LOKINET_APPLE_BUILD 0)
|
||||
set(LOKINET_APPLE_BUILD 1)
|
||||
endif()
|
||||
|
||||
set(RELEASE_MOTTO "Gluten Free Edition" CACHE STRING "Release motto")
|
||||
|
@ -60,6 +60,7 @@ option(WITH_TESTS "build unit tests" OFF)
|
|||
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)
|
||||
|
||||
include(cmake/enable_lto.cmake)
|
||||
|
||||
|
@ -82,7 +83,7 @@ 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)
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "")
|
||||
endif()
|
||||
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
@ -105,6 +106,7 @@ endif()
|
|||
|
||||
include(cmake/solaris.cmake)
|
||||
include(cmake/win32.cmake)
|
||||
include(cmake/macos.cmake)
|
||||
|
||||
# No in-source building
|
||||
include(MacroEnsureOutOfSourceBuild)
|
||||
|
@ -299,6 +301,12 @@ endif()
|
|||
|
||||
add_subdirectory(docs)
|
||||
|
||||
include(cmake/gui.cmake)
|
||||
|
||||
if(APPLE)
|
||||
macos_target_setup()
|
||||
endif()
|
||||
|
||||
# uninstall target
|
||||
if(NOT TARGET uninstall)
|
||||
configure_file(
|
||||
|
@ -311,6 +319,6 @@ if(NOT TARGET uninstall)
|
|||
endif()
|
||||
|
||||
|
||||
if(BUILD_PACKAGE AND NOT APPLE)
|
||||
if(BUILD_PACKAGE)
|
||||
include(cmake/installer.cmake)
|
||||
endif()
|
||||
|
|
|
@ -315,8 +315,11 @@ build_external(sodium CONFIGURE_COMMAND ./configure ${cross_host} ${cross_rc} --
|
|||
--enable-static --with-pic "CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}")
|
||||
add_static_target(sodium sodium_external libsodium.a)
|
||||
|
||||
build_external(sqlite3)
|
||||
add_static_target(sqlite3 sqlite3_external libsqlite3.a)
|
||||
|
||||
if(WITH_PEERSTATS_BACKEND)
|
||||
build_external(sqlite3)
|
||||
add_static_target(sqlite3 sqlite3_external libsqlite3.a)
|
||||
endif()
|
||||
|
||||
|
||||
if(ARCH_TRIPLET MATCHES mingw)
|
||||
|
@ -328,7 +331,9 @@ endif()
|
|||
|
||||
if(CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
|
||||
set(zmq_patch
|
||||
PATCH_COMMAND ${PROJECT_SOURCE_DIR}/contrib/apply-patches.sh ${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-wepoll.patch ${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-closesocket.patch)
|
||||
PATCH_COMMAND ${PROJECT_SOURCE_DIR}/contrib/apply-patches.sh
|
||||
${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-wepoll.patch
|
||||
${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-unistd.patch)
|
||||
endif()
|
||||
|
||||
build_external(zmq
|
||||
|
@ -351,6 +356,15 @@ set_target_properties(libzmq PROPERTIES
|
|||
INTERFACE_LINK_LIBRARIES "${libzmq_link_libs}"
|
||||
INTERFACE_COMPILE_DEFINITIONS "ZMQ_STATIC")
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
# Everything that follows is *only* for lokinet-bootstrap (i.e. if adding new deps put them *above*
|
||||
# this).
|
||||
#
|
||||
#
|
||||
#
|
||||
if(NOT WITH_BOOTSTRAP)
|
||||
return()
|
||||
endif()
|
||||
|
@ -420,7 +434,7 @@ foreach(curl_arch ${curl_arches})
|
|||
list(APPEND curl_lib_outputs ${curl_prefix}/lib/libcurl.a)
|
||||
endforeach()
|
||||
|
||||
message(STATUS "TARGETS: ${curl_lib_targets}")
|
||||
|
||||
|
||||
if(IOS AND num_arches GREATER 1)
|
||||
# We are building multiple architectures for different iOS devices, so we need to glue the
|
||||
|
|
|
@ -44,6 +44,7 @@ if(filesystem_is_good EQUAL 1)
|
|||
else()
|
||||
# Probably broken AF macos
|
||||
message(STATUS "std::filesystem is not available, apparently this compiler isn't C++17 compliant; falling back to ghc::filesystem")
|
||||
set(GHC_FILESYSTEM_WITH_INSTALL OFF CACHE INTERNAL "")
|
||||
add_subdirectory(external/ghc-filesystem)
|
||||
target_link_libraries(filesystem INTERFACE ghc_filesystem)
|
||||
target_compile_definitions(filesystem INTERFACE USE_GHC_FILESYSTEM)
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
|
||||
set(default_build_gui OFF)
|
||||
set(default_gui_target pack)
|
||||
if(APPLE)
|
||||
set(default_build_gui ON)
|
||||
set(default_gui_target macos:raw)
|
||||
elseif(WIN32)
|
||||
set(default_build_gui ON)
|
||||
set(default_gui_target win32)
|
||||
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")
|
||||
|
||||
find_program(YARN NAMES yarn yarnpkg REQUIRED)
|
||||
message(STATUS "Building lokinet-gui with yarn ${YARN}, target ${GUI_YARN_TARGET}")
|
||||
set(wine_env)
|
||||
if(WIN32)
|
||||
set(wine_env 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(APPLE)
|
||||
add_custom_target(assemble_gui ALL
|
||||
DEPENDS assemble lokinet-gui
|
||||
COMMAND mkdir "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Helpers"
|
||||
COMMAND cp -a "${PROJECT_SOURCE_DIR}/gui/release/mac/Lokinet-GUI.app" "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Helpers/"
|
||||
COMMAND mkdir -p "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Resources/en.lproj"
|
||||
COMMAND cp "${PROJECT_SOURCE_DIR}/contrib/macos/InfoPlist.strings" "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Resources/en.lproj/"
|
||||
COMMAND cp "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Resources/icon.icns" "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Helpers/Lokinet-GUI.app/Contents/Resources/icon.icns"
|
||||
COMMAND cp "${PROJECT_SOURCE_DIR}/contrib/macos/InfoPlist.strings" "${PROJECT_BINARY_DIR}/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}"
|
||||
"${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Helpers/Lokinet-GUI.app/Contents/Info.plist"
|
||||
)
|
||||
|
||||
elseif(WIN32)
|
||||
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/gui")
|
||||
add_custom_target(copy_gui ALL
|
||||
DEPENDS lokinet lokinet-gui
|
||||
# FIXME: we really shouldn't be building inside the source directory but this is npm...
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/gui/release/Lokinet-GUI_portable.exe"
|
||||
"${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 lokinet-gui")
|
||||
endif()
|
|
@ -5,6 +5,8 @@ set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
|
|||
|
||||
if(WIN32)
|
||||
include(cmake/win32_installer_deps.cmake)
|
||||
elseif(APPLE)
|
||||
set(CPACK_GENERATOR DragNDrop;ZIP)
|
||||
endif()
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
if(NOT APPLE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
option(MACOS_SYSTEM_EXTENSION
|
||||
"Build the network extension as a system extension rather than a plugin. This must be ON for non-app store release builds, and must be OFF for dev builds and Mac App Store distribution builds"
|
||||
OFF)
|
||||
option(CODESIGN "codesign the resulting app and extension" ON)
|
||||
set(CODESIGN_ID "" CACHE STRING "codesign the macos app using this key identity; if empty we'll try to guess")
|
||||
set(default_profile_type "dev")
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(default_profile_type "release")
|
||||
endif()
|
||||
set(CODESIGN_PROFILE "${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.${default_profile_type}.provisionprofile" CACHE FILEPATH
|
||||
"Path to a .provisionprofile to use for the main app")
|
||||
|
||||
if(CODESIGN AND NOT CODESIGN_ID)
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(codesign_cert_pattern "Developer ID Application")
|
||||
else()
|
||||
set(codesign_cert_pattern "Apple Development")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND security find-identity -v -p codesigning
|
||||
COMMAND sed -n "s/^ *[0-9][0-9]*) *\\([A-F0-9]\\{40\\}\\) *\"\\(${codesign_cert_pattern}.*\\)\"\$/\\1 \\2/p"
|
||||
RESULT_VARIABLE find_id_exit_code
|
||||
OUTPUT_VARIABLE find_id_output)
|
||||
if(NOT find_id_exit_code EQUAL 0)
|
||||
message(FATAL_ERROR "Finding signing identities with security find-identity failed; try specifying an id using -DCODESIGN_ID=...")
|
||||
endif()
|
||||
|
||||
string(REGEX MATCHALL "(^|\n)[0-9A-F]+" find_id_sign_id "${find_id_output}")
|
||||
if(NOT find_id_sign_id)
|
||||
message(FATAL_ERROR "Did not find any \"${codesign_cert_pattern}\" identity; try specifying an id using -DCODESIGN_ID=...")
|
||||
endif()
|
||||
if (find_id_sign_id MATCHES ";")
|
||||
message(FATAL_ERROR "Found multiple \"${codesign_cert_pattern}\" identities:\n${find_id_output}\nSpecify an identify using -DCODESIGN_ID=...")
|
||||
endif()
|
||||
set(CODESIGN_ID "${find_id_sign_id}" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if(CODESIGN)
|
||||
message(STATUS "Codesigning using ${CODESIGN_ID}")
|
||||
|
||||
if (NOT MACOS_NOTARIZE_USER AND NOT MACOS_NOTARIZE_PASS AND NOT MACOS_NOTARIZE_ASC AND EXISTS "$ENV{HOME}/.notarization.cmake")
|
||||
message(STATUS "Loading notarization info from ~/.notarization.cmake")
|
||||
include("$ENV{HOME}/.notarization.cmake")
|
||||
endif()
|
||||
|
||||
if (MACOS_NOTARIZE_USER AND MACOS_NOTARIZE_PASS AND MACOS_NOTARIZE_ASC)
|
||||
message(STATUS "Enabling notarization with account ${MACOS_NOTARIZE_ASC}/${MACOS_NOTARIZE_USER}")
|
||||
else()
|
||||
message(WARNING "You have not set one or more of MACOS_NOTARIZE_USER, MACOS_NOTARIZE_PASS, MACOS_NOTARIZE_ASC: notarization will fail; see contrib/macos/README.txt")
|
||||
endif()
|
||||
|
||||
else()
|
||||
message(WARNING "Codesigning disabled; the resulting build will not run on most macOS systems")
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT CODESIGN_PROFILE)
|
||||
message(WARNING "Missing a CODESIGN_PROFILE provisioning profile: Apple will most likely log an uninformative error message to the system log and then kill harmless kittens if you try to run the result")
|
||||
endif()
|
||||
if(NOT EXISTS "${CODESIGN_PROFILE}")
|
||||
message(FATAL_ERROR "Provisioning profile ${CODESIGN_PROFILE} does not exist; fix your -DCODESIGN_PROFILE path")
|
||||
endif()
|
||||
message(STATUS "Using ${CODESIGN_PROFILE} provisioning profile")
|
||||
|
||||
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(lokinet_ext_dir Contents/Library/SystemExtensions)
|
||||
else()
|
||||
set(lokinet_ext_dir Contents/PlugIns)
|
||||
endif()
|
||||
|
||||
if(CODESIGN)
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(LOKINET_ENTITLEMENTS_TYPE sysext)
|
||||
set(notarize_py_is_sysext True)
|
||||
else()
|
||||
set(LOKINET_ENTITLEMENTS_TYPE plugin)
|
||||
set(notarize_py_is_sysext False)
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in"
|
||||
"${PROJECT_BINARY_DIR}/sign.sh"
|
||||
@ONLY)
|
||||
|
||||
add_custom_target(
|
||||
sign
|
||||
DEPENDS "${PROJECT_BINARY_DIR}/sign.sh"
|
||||
COMMAND "${PROJECT_BINARY_DIR}/sign.sh"
|
||||
)
|
||||
|
||||
if(MACOS_NOTARIZE_USER AND MACOS_NOTARIZE_PASS AND MACOS_NOTARIZE_ASC)
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/contrib/macos/notarize.py.in"
|
||||
"${PROJECT_BINARY_DIR}/notarize.py"
|
||||
@ONLY)
|
||||
add_custom_target(
|
||||
notarize
|
||||
DEPENDS "${PROJECT_BINARY_DIR}/notarize.py" sign
|
||||
COMMAND "${PROJECT_BINARY_DIR}/notarize.py"
|
||||
)
|
||||
else()
|
||||
message(WARNING "You have not set one or more of MACOS_NOTARIZE_USER, MACOS_NOTARIZE_PASS, MACOS_NOTARIZE_ASC: notarization disabled")
|
||||
endif()
|
||||
else()
|
||||
add_custom_target(sign COMMAND "true")
|
||||
add_custom_target(notarize DEPENDS sign COMMAND "true")
|
||||
endif()
|
||||
|
||||
|
||||
# Called later to set things up, after the main lokinet targets are set up
|
||||
function(macos_target_setup)
|
||||
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
target_compile_definitions(lokinet PRIVATE MACOS_SYSTEM_EXTENSION)
|
||||
endif()
|
||||
|
||||
set_target_properties(lokinet
|
||||
PROPERTIES
|
||||
OUTPUT_NAME Lokinet
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "Lokinet"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${lokinet_VERSION}"
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "${lokinet_VERSION}"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.lokinet"
|
||||
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.Info.plist.in"
|
||||
MACOSX_BUNDLE_COPYRIGHT "© 2022, The Oxen Project"
|
||||
)
|
||||
|
||||
add_custom_target(copy_bootstrap
|
||||
DEPENDS lokinet-extension
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/bootstrap/mainnet.signed
|
||||
$<TARGET_BUNDLE_DIR:lokinet-extension>/Contents/Resources/bootstrap.signed
|
||||
)
|
||||
|
||||
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)
|
||||
add_custom_target(icon DEPENDS ${mac_icon})
|
||||
|
||||
|
||||
add_dependencies(lokinet lokinet-extension icon)
|
||||
|
||||
|
||||
if(CODESIGN_PROFILE)
|
||||
add_custom_target(copy_prov_prof
|
||||
DEPENDS lokinet
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CODESIGN_PROFILE}
|
||||
$<TARGET_BUNDLE_DIR:lokinet>/Contents/embedded.provisionprofile
|
||||
)
|
||||
else()
|
||||
add_custom_target(copy_prov_prof COMMAND true)
|
||||
endif()
|
||||
|
||||
add_custom_target(assemble ALL
|
||||
DEPENDS lokinet lokinet-extension icon copy_prov_prof copy_bootstrap
|
||||
COMMAND rm -rf "${PROJECT_BINARY_DIR}/Lokinet.app"
|
||||
COMMAND cp -a $<TARGET_BUNDLE_DIR:lokinet> "${PROJECT_BINARY_DIR}/Lokinet.app"
|
||||
COMMAND mkdir -p "${PROJECT_BINARY_DIR}/Lokinet.app/${lokinet_ext_dir}"
|
||||
COMMAND cp -a $<TARGET_BUNDLE_DIR:lokinet-extension> "${PROJECT_BINARY_DIR}/Lokinet.app/${lokinet_ext_dir}/"
|
||||
COMMAND mkdir -p "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Resources"
|
||||
COMMAND cp -a "${mac_icon}" "${PROJECT_BINARY_DIR}/Lokinet.app/Contents/Resources/icon.icns"
|
||||
)
|
||||
|
||||
if(CODESIGN)
|
||||
add_dependencies(sign assemble)
|
||||
endif()
|
||||
endfunction()
|
|
@ -1,8 +1,3 @@
|
|||
if(NOT GUI_ZIP_URL)
|
||||
set(GUI_ZIP_URL "https://oxen.rocks/oxen-io/lokinet-gui/dev/lokinet-windows-x64-20220331T180338Z-569f90ad8.zip")
|
||||
set(GUI_ZIP_HASH_OPTS EXPECTED_HASH SHA256=316f10489f5907bfa9c74b21f8ef2fdd7b7c7e6a0f5bcedaed2ee5f4004eab52)
|
||||
endif()
|
||||
|
||||
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")
|
||||
|
@ -11,13 +6,25 @@ file(DOWNLOAD
|
|||
${TUNTAP_URL}
|
||||
${TUNTAP_EXE})
|
||||
|
||||
file(DOWNLOAD
|
||||
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")
|
||||
set(GUI_ZIP_HASH_OPTS EXPECTED_HASH SHA256=316f10489f5907bfa9c74b21f8ef2fdd7b7c7e6a0f5bcedaed2ee5f4004eab52)
|
||||
endif()
|
||||
|
||||
file(DOWNLOAD
|
||||
${GUI_ZIP_URL}
|
||||
${CMAKE_BINARY_DIR}/lokinet-gui.zip
|
||||
${GUI_ZIP_HASH_OPTS})
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf ${CMAKE_BINARY_DIR}/lokinet-gui.zip
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
# We expect the produced .zip file above to extract to ./gui/lokinet-gui.exe
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf ${CMAKE_BINARY_DIR}/lokinet-gui.zip
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
if(NOT EXISTS ${CMAKE_BINARY_DIR}/gui/lokinet-gui.exe)
|
||||
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)
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 1024 1024" style="enable-background:new 0 0 1024 1024;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M897.5,1024H126.5C56.6,1024,0,967.4,0,897.5V126.5C0,56.6,56.6,0,126.5,0h771.1C967.4,0,1024,56.6,1024,126.5
|
||||
v771.1C1024,967.4,967.4,1024,897.5,1024z"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon points="585.2,658.9 512,732.1 438.8,658.9 365.1,732.1 512,879 658.9,732.1 "/>
|
||||
<polygon points="658.9,585.2 732.1,512 658.9,438.8 732.1,365.1 879,512 732.1,658.9 "/>
|
||||
<polygon points="365.1,438.8 291.9,512 365.1,585.2 291.9,658.9 145,512 291.9,365.1 "/>
|
||||
<polygon points="438.8,365.1 512,291.9 585.2,365.1 658.9,291.9 512,145 365.1,291.9 "/>
|
||||
<rect x="533.4" y="533.3" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -242.3375 585.3179)" width="103.9" height="103.9"/>
|
||||
<rect x="386.7" y="386.9" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -181.837 438.6521)" width="103.9" height="103.9"/>
|
||||
<rect x="533.2" y="386.7" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -138.7545 542.2352)" width="103.9" height="103.9"/>
|
||||
<rect x="386.9" y="533.5" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -285.4199 481.7348)" width="103.9" height="103.9"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -18,22 +18,16 @@ cd build-mac
|
|||
cmake \
|
||||
-G Ninja \
|
||||
-DBUILD_STATIC_DEPS=ON \
|
||||
-DBUILD_PACKAGE=ON \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DBUILD_LIBLOKINET=OFF \
|
||||
-DWITH_TESTS=OFF \
|
||||
-DWITH_BOOTSTRAP=OFF \
|
||||
-DNATIVE_BUILD=OFF \
|
||||
-DSTATIC_LINK=ON \
|
||||
-DWITH_SYSTEMD=OFF \
|
||||
-DFORCE_OXENMQ_SUBMODULE=ON \
|
||||
-DSUBMODULE_CHECK=OFF \
|
||||
-DWITH_LTO=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
"$@" \
|
||||
..
|
||||
ninja sign
|
||||
ninja -j1
|
||||
|
||||
echo -e "Build complete, your app is here:\n"
|
||||
ls -lad $(pwd)/daemon/lokinet.app
|
||||
ls -lad $(pwd)/Lokinet.app
|
||||
echo ""
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Lokinet</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>MacOS/lokinet</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.loki-project.lokinet</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>lokinet</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@lokinet_VERSION@</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@lokinet_VERSION@.@LOKINET_APPLE_BUILD@</string>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
|
@ -1,40 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Lokinet</string>
|
||||
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>lokinet-extension</string>
|
||||
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.loki-project.lokinet.network-extension</string>
|
||||
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>lokinet</string>
|
||||
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@lokinet_VERSION@</string>
|
||||
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>11.0</string>
|
||||
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.networkextension.packet-tunnel</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>LLARPPacketTunnel</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,38 +0,0 @@
|
|||
This directory contains the magical incantations and random voodoo symbols needed to coax an Apple
|
||||
build. There's no reason builds have to be this stupid, except that Apple wants to funnel everyone
|
||||
into the no-CI, no-help, undocumented, non-toy-apps-need-not-apply modern Apple culture.
|
||||
|
||||
This is disgusting.
|
||||
|
||||
But it gets worse.
|
||||
|
||||
The following two files, in particular, are the very worst manifestations of this already toxic
|
||||
Apple cancer: they are required for proper permissions to run on macOS, are undocumented, and can
|
||||
only be regenerated through the entirely closed source Apple Developer backend, for which you have
|
||||
to pay money first to get a team account (a personal account will not work), and they lock the
|
||||
resulting binaries to only run on individually selected Apple computers selected at the time the
|
||||
profile is provisioned (with no ability to allow it to run anywhere).
|
||||
|
||||
lokinet.provisionprofile
|
||||
lokinet-extension.provisionprofile
|
||||
|
||||
This is actively hostile to open source development, but that is nothing new for Apple.
|
||||
|
||||
In order to make things work, you'll have to replace these provisioning profiles with your own
|
||||
(after paying Apple for the privilege of developing on their platform, of course) and change all the
|
||||
team/application/bundle IDs to reference your own team, matching the provisioning profiles. The
|
||||
provisioning profiles must be a "macOS Development" provisioning profile, and must include the
|
||||
signing keys and the authorized devices on which you want to run it. (The profiles bundled in this
|
||||
repository contains the lokinet team's "Apple Development" keys associated with the Oxen project,
|
||||
and mac dev boxes. This is *useless* for anyone else).
|
||||
|
||||
Also take note that you *must not* put a development build `lokinet.app` inside /Applications
|
||||
because if you do, it won't work because *on top* of the ridiculous signing and entitlement bullshit
|
||||
that Apple makes you jump through, the rules *also* differ for binaries placed in /Applications
|
||||
versus binaries placed elsewhere, but like everything else here, it is entirely undocumented.
|
||||
|
||||
If you are reading this to try to build Lokinet for yourself for an Apple operating system and
|
||||
simultaneously care about open source, privacy, or freedom then you, my friend, are a walking
|
||||
contradiction: you are trying to get Lokinet to work on a platform that actively despises open
|
||||
source, privacy, and freedom. Even Windows is a better choice in all of these categories than
|
||||
Apple.
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Lokinet Network Extension</string>
|
||||
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>org.lokinet.network-extension</string>
|
||||
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.lokinet.network-extension</string>
|
||||
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>SYSX</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>org.lokinet.network-extension</string>
|
||||
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@lokinet_VERSION@.@LOKINET_APPLE_BUILD@</string>
|
||||
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@lokinet_VERSION@</string>
|
||||
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.15</string>
|
||||
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2022 The Oxen Project, licensed under GPLv3-or-later</string>
|
||||
|
||||
<key>NSSystemExtensionUsageDescription</key>
|
||||
<string>Provides Lokinet Network connectivity.</string>
|
||||
|
||||
<key>NetworkExtension</key>
|
||||
<dict>
|
||||
<key>NEMachServiceName</key>
|
||||
<string>SUQ8J2PCT7.org.lokinet.network-extension</string>
|
||||
|
||||
<key>NEProviderClasses</key>
|
||||
<dict>
|
||||
<key>com.apple.networkextension.packet-tunnel</key>
|
||||
<string>LLARPPacketTunnel</string>
|
||||
|
||||
<key>com.apple.networkextension.dns-proxy</key>
|
||||
<string>LLARPDNSProxy</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
|
@ -3,11 +3,12 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.application-identifier</key>
|
||||
<string>SUQ8J2PCT7.com.loki-project.lokinet.network-extension</string>
|
||||
<string>SUQ8J2PCT7.org.lokinet.network-extension</string>
|
||||
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
<string>dns-proxy</string>
|
||||
</array>
|
||||
|
||||
<key>com.apple.developer.team-identifier</key>
|
||||
|
@ -16,9 +17,6 @@
|
|||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.get-task-allow</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.application-identifier</key>
|
||||
<string>SUQ8J2PCT7.org.lokinet.network-extension</string>
|
||||
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider-systemextension</string>
|
||||
<string>dns-proxy-systemextension</string>
|
||||
</array>
|
||||
|
||||
<key>com.apple.developer.team-identifier</key>
|
||||
<string>SUQ8J2PCT7</string>
|
||||
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>SUQ8J2PCT7.org.lokinet</string>
|
||||
</array>
|
||||
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Lokinet</string>
|
||||
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.lokinet</string>
|
||||
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>Lokinet</string>
|
||||
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>icon.icns</string>
|
||||
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@lokinet_VERSION@</string>
|
||||
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@lokinet_VERSION@.@LOKINET_APPLE_BUILD@</string>
|
||||
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.15</string>
|
||||
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2022 The Oxen Project, licensed under GPLv3-or-later</string>
|
||||
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
|
||||
<key>LSHasLocalizedDisplayName</key>
|
||||
<true/>
|
||||
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
|
@ -3,13 +3,13 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.application-identifier</key>
|
||||
<string>SUQ8J2PCT7.com.loki-project.lokinet</string>
|
||||
<string>SUQ8J2PCT7.org.lokinet</string>
|
||||
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
<string>dns-proxy</string>
|
||||
<string>dns-settings</string>
|
||||
<string>dns-proxy</string>
|
||||
<string>dns-settings</string>
|
||||
</array>
|
||||
|
||||
<key>com.apple.developer.team-identifier</key>
|
||||
|
@ -18,13 +18,10 @@
|
|||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.get-task-allow</key>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.network.server</key>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
|
||||
</dict>
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.application-identifier</key>
|
||||
<string>SUQ8J2PCT7.org.lokinet</string>
|
||||
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider-systemextension</string>
|
||||
<string>dns-proxy-systemextension</string>
|
||||
<string>dns-settings</string>
|
||||
</array>
|
||||
|
||||
<key>com.apple.developer.team-identifier</key>
|
||||
<string>SUQ8J2PCT7</string>
|
||||
|
||||
<key>com.apple.developer.system-extension.install</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>SUQ8J2PCT7.org.lokinet</string>
|
||||
</array>
|
||||
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
|
||||
</dict>
|
||||
</plist>
|
|
@ -14,7 +14,7 @@ done
|
|||
mv "${outdir}/icon_1024x1024.png" "${outdir}/icon_512x512@2x.png"
|
||||
for size in 16 32 128 256; do
|
||||
double=$((size * 2))
|
||||
cp "${outdir}/icon_${double}x${double}.png" "${outdir}/icon_${size}x${size}@2x.png"
|
||||
ln -f "${outdir}/icon_${double}x${double}.png" "${outdir}/icon_${size}x${size}@2x.png"
|
||||
done
|
||||
|
||||
iconutil -c icns "${outdir}"
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>network.loki.lokinet.daemon</string>
|
||||
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/var/lib/lokinet/lokinet_macos_daemon_script.sh</string>
|
||||
</array>
|
||||
|
||||
<!-- Keep Lokinet alive unless magic file exists -->
|
||||
<key>KeepAlive</key>
|
||||
<dict>
|
||||
<key>PathState</key>
|
||||
<dict>
|
||||
<key>/var/lib/lokinet/suspend-launchd-service</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>/var/log/lokinet.log</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -4,21 +4,47 @@ import sys
|
|||
import plistlib
|
||||
import subprocess
|
||||
import time
|
||||
import os
|
||||
import os.path
|
||||
|
||||
def bold_red(x):
|
||||
return "\x1b[31;1m" + x + "\x1b[0m"
|
||||
|
||||
if not @notarize_py_is_sysext@:
|
||||
print(bold_red("\nUnable to notarize: this lokinet is not built as a system extension\n"), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if not all(("@MACOS_NOTARIZE_USER@", "@MACOS_NOTARIZE_PASS@", "@MACOS_NOTARIZE_ASC@")):
|
||||
print(bold_red("\nUnable to notarize: one or more required notarization variable not set; see contrib/macos/README.txt\n") +
|
||||
" Called with -DMACOS_NOTARIZE_USER=@MACOS_NOTARIZE_USER@\n"
|
||||
" -DMACOS_NOTARIZE_PASS=@MACOS_NOTARIZE_PASS@\n"
|
||||
" -DMACOS_NOTARIZE_ASC=@MACOS_NOTARIZE_ASC@\n",
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
os.chdir("@PROJECT_BINARY_DIR@")
|
||||
app = "Lokinet.app"
|
||||
zipfile = f"{app}.notarize.zip"
|
||||
print(f"Creating {zipfile} from {app}")
|
||||
if os.path.exists(zipfile):
|
||||
os.remove(zipfile)
|
||||
subprocess.run(['ditto', '-v', '-c', '-k', '--sequesterRsrc', '--keepParent', app, zipfile])
|
||||
|
||||
pkg = "lokinet-@PROJECT_VERSION@-Darwin.pkg"
|
||||
userpass = ('--username', "@MACOS_NOTARIZE_USER@", '--password', "@MACOS_NOTARIZE_PASS@")
|
||||
print("Submitting {} for notarization; this may take a minute...".format(pkg))
|
||||
print("Submitting {} for notarization; this may take a minute...".format(zipfile))
|
||||
|
||||
started = time.time()
|
||||
result = subprocess.run([
|
||||
command = [
|
||||
'xcrun', 'altool',
|
||||
'--notarize-app',
|
||||
'--primary-bundle-id', 'org.lokinet.lokinet.pkg.@PROJECT_VERSION@',
|
||||
'--primary-bundle-id', 'org.lokinet.@PROJECT_VERSION@',
|
||||
*userpass,
|
||||
'--asc-provider', "@MACOS_NOTARIZE_ASC@",
|
||||
'--file', pkg,
|
||||
'--file', zipfile,
|
||||
'--output-format', 'xml'
|
||||
], stdout=subprocess.PIPE)
|
||||
]
|
||||
print(command)
|
||||
result = subprocess.run(command, stdout=subprocess.PIPE)
|
||||
|
||||
data = plistlib.loads(result.stdout)
|
||||
if 'success-message' not in data or 'notarization-upload' not in data or 'RequestUUID' not in data['notarization-upload']:
|
||||
|
@ -42,24 +68,27 @@ while not done:
|
|||
'--notarization-info', uuid,
|
||||
*userpass,
|
||||
'--output-format', 'xml'
|
||||
], stdout=subprocess.PIPE)
|
||||
result.check_returncode()
|
||||
data = plistlib.loads(result.stdout)
|
||||
if 'notarization-info' not in data or 'Status' not in data['notarization-info']:
|
||||
status = 'Request failed'
|
||||
], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
if result.returncode == 1 and b'Gateway Timeout' in result.stderr:
|
||||
status = "Apple's servers are trash (aka Gateway Timeout)"
|
||||
else:
|
||||
status = data['notarization-info']['Status Message'] if 'Status Message' in data['notarization-info'] else ''
|
||||
st = data['notarization-info']['Status']
|
||||
if st == 'success':
|
||||
success = True
|
||||
done = True
|
||||
elif st == 'invalid':
|
||||
done = True
|
||||
elif st == 'in progress' and len(status) == 0:
|
||||
status = 'Notarization in progress'
|
||||
result.check_returncode()
|
||||
data = plistlib.loads(result.stdout)
|
||||
if 'notarization-info' not in data or 'Status' not in data['notarization-info']:
|
||||
status = 'Request failed'
|
||||
else:
|
||||
status = data['notarization-info']['Status Message'] if 'Status Message' in data['notarization-info'] else ''
|
||||
st = data['notarization-info']['Status']
|
||||
if st == 'success':
|
||||
success = True
|
||||
done = True
|
||||
elif st == 'invalid':
|
||||
done = True
|
||||
elif st == 'in progress' and len(status) == 0:
|
||||
status = 'Notarization in progress'
|
||||
|
||||
if done and 'LogFileURL' in data['notarization-info']:
|
||||
status += '\n\nlog file: {}'.format(data['notarization-info']['LogFileURL'])
|
||||
if done and 'LogFileURL' in data['notarization-info']:
|
||||
status += '\n\nlog file: {}'.format(data['notarization-info']['LogFileURL'])
|
||||
|
||||
elapsed = time.time() - started_waiting
|
||||
mins, secs = int(elapsed // 60), int(elapsed % 60)
|
||||
|
@ -70,7 +99,12 @@ print("\n")
|
|||
if not success:
|
||||
sys.exit(42)
|
||||
|
||||
print("Stapling {}".format(pkg))
|
||||
result = subprocess.run(['xcrun', 'stapler', 'staple', pkg])
|
||||
if os.path.exists(zipfile):
|
||||
os.remove(zipfile)
|
||||
|
||||
print("Stapling {}...".format(app), end='')
|
||||
result = subprocess.run(['xcrun', 'stapler', 'staple', app])
|
||||
|
||||
result.check_returncode()
|
||||
|
||||
print(" success.\n")
|
||||
|
|
|
@ -1,10 +1,72 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
codesign --verbose=4 --force -s "@CODESIGN_APPEX@" \
|
||||
--entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-extension.entitlements.plist" \
|
||||
--deep --strict --timestamp --options=runtime "@SIGN_TARGET@/Contents/PlugIns/lokinet-extension.appex"
|
||||
for file in "@SIGN_TARGET@/Contents/MacOS/lokinet" "@SIGN_TARGET@" ; do
|
||||
codesign --verbose=4 --force -s "@CODESIGN_APP@" \
|
||||
--entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet.entitlements.plist" \
|
||||
--deep --strict --timestamp --options=runtime "$file"
|
||||
|
||||
if [ "@CODESIGN@" != "ON" ]; then
|
||||
echo "Cannot codesign: this build was not configured with codesigning" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
signit() {
|
||||
target="$1"
|
||||
entitlements="$2"
|
||||
echo -e "\n\e[33;1mSigning ${target/*\/Lokinet.app/Lokinet.app}...\e[0m" >&2
|
||||
codesign \
|
||||
--verbose=4 \
|
||||
--force \
|
||||
-s "@CODESIGN_ID@" \
|
||||
--entitlements "$entitlements" \
|
||||
--strict \
|
||||
--timestamp \
|
||||
--options=runtime \
|
||||
"$target"
|
||||
}
|
||||
|
||||
gui_entitlements="@PROJECT_SOURCE_DIR@/gui/node_modules/app-builder-lib/templates/entitlements.mac.plist"
|
||||
ext_entitlements="@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-extension.@LOKINET_ENTITLEMENTS_TYPE@.entitlements.plist"
|
||||
app_entitlements="@PROJECT_SOURCE_DIR@/contrib/macos/lokinet.@LOKINET_ENTITLEMENTS_TYPE@.entitlements.plist"
|
||||
|
||||
SIGN_TARGET="@PROJECT_BINARY_DIR@/Lokinet.app"
|
||||
|
||||
for ext in systemextension appex; do
|
||||
netext="$SIGN_TARGET/@lokinet_ext_dir@/org.lokinet.network-extension.$ext"
|
||||
if [ -e "$netext" ]; then
|
||||
signit "$netext" "$ext_entitlements"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "@BUILD_GUI@" == "ON" ]; then
|
||||
gui_app="$SIGN_TARGET"/Contents/Helpers/Lokinet-GUI.app
|
||||
gui_sign_targets=()
|
||||
for bundle in \
|
||||
"$gui_app"/Contents/Frameworks/*.framework \
|
||||
"$gui_app"/Contents/Frameworks/*.app
|
||||
do
|
||||
|
||||
if [ -d "$bundle/Libraries" ]; then
|
||||
gui_sign_targets+=("$bundle"/Libraries/*.dylib)
|
||||
fi
|
||||
if [ -d "$bundle/Helpers" ]; then
|
||||
gui_sign_targets+=("$bundle"/Helpers/*)
|
||||
fi
|
||||
if [ -d "$bundle/Resources" ]; then
|
||||
for f in "$bundle/Resources"/*; do
|
||||
if [[ -f "$f" && -x "$f" && "$(file -b "$f")" == Mach-O* ]]; then
|
||||
gui_sign_targets+=("$f")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
gui_sign_targets+=("$bundle")
|
||||
done
|
||||
|
||||
gui_sign_targets+=("$gui_app")
|
||||
|
||||
for target in "${gui_sign_targets[@]}"; do
|
||||
signit "$target" "$gui_entitlements"
|
||||
done
|
||||
|
||||
signit "$SIGN_TARGET"/Contents/MacOS/Lokinet "$app_entitlements"
|
||||
fi
|
||||
|
||||
signit "$SIGN_TARGET" "$app_entitlements"
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
diff --git a/tests/testutil.hpp b/tests/testutil.hpp
|
||||
index c6f5e4de..6a1c8bb8 100644
|
||||
--- a/tests/testutil.hpp
|
||||
+++ b/tests/testutil.hpp
|
||||
@@ -102,7 +102,6 @@ const uint8_t zmtp_ready_sub[27] = {
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <stdexcept>
|
||||
-#define close closesocket
|
||||
typedef int socket_size_t;
|
||||
inline const char *as_setsockopt_opt_t (const void *opt)
|
||||
{
|
|
@ -0,0 +1,14 @@
|
|||
diff --git a/tests/testutil.hpp b/tests/testutil.hpp
|
||||
index c6f5e4de78..09b9fa77e5 100644
|
||||
--- a/tests/testutil.hpp
|
||||
+++ b/tests/testutil.hpp
|
||||
@@ -41,6 +41,9 @@
|
||||
// For AF_INET and IPPROTO_TCP
|
||||
#if defined _WIN32
|
||||
#include "../src/windows.hpp"
|
||||
+#if defined(__MINGW32__)
|
||||
+#include <unistd.h>
|
||||
+#endif
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
|
@ -14,6 +14,7 @@ cmake \
|
|||
-DCMAKE_EXE_LINKER_FLAGS=-fstack-protector \
|
||||
-DCMAKE_CXX_FLAGS=-fdiagnostics-color=always \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$root/contrib/cross/mingw64.cmake" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_STATIC_DEPS=ON \
|
||||
-DBUILD_PACKAGE=ON \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
|
@ -28,6 +29,5 @@ cmake \
|
|||
-DFORCE_FMT_SUBMODULE=ON \
|
||||
-DFORCE_SPDLOG_SUBMODULE=ON \
|
||||
-DFORCE_NLOHMANN_SUBMODULE=ON \
|
||||
-DSUBMODULE_CHECK=OFF \
|
||||
-DWITH_LTO=OFF \
|
||||
$@
|
||||
|
|
|
@ -10,5 +10,5 @@ set +x
|
|||
|
||||
root="$(readlink -f $(dirname $0)/../)"
|
||||
cd "$root"
|
||||
./contrib/windows-configure.sh . build-windows $@
|
||||
./contrib/windows-configure.sh . build-windows "$@"
|
||||
make package -j${JOBS:-$(nproc)} -C build-windows
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
set(exetargets lokinet)
|
||||
|
||||
add_executable(lokinet-vpn lokinet-vpn.cpp)
|
||||
if(APPLE)
|
||||
add_executable(lokinet lokinet.swift)
|
||||
enable_lto(lokinet)
|
||||
else()
|
||||
add_executable(lokinet lokinet.cpp)
|
||||
enable_lto(lokinet lokinet-vpn)
|
||||
endif()
|
||||
add_executable(lokinet-vpn lokinet-vpn.cpp)
|
||||
enable_lto(lokinet lokinet-vpn)
|
||||
list(APPEND exetargets lokinet-vpn)
|
||||
|
||||
if(WITH_BOOTSTRAP)
|
||||
add_executable(lokinet-bootstrap lokinet-bootstrap.cpp)
|
||||
list(APPEND exetargets lokinet-bootstrap)
|
||||
enable_lto(lokinet-bootstrap)
|
||||
endif()
|
||||
|
||||
|
@ -42,11 +45,6 @@ if(WITH_BOOTSTRAP)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
set(exetargets lokinet lokinet-vpn)
|
||||
if(WITH_BOOTSTRAP)
|
||||
list(APPEND exetargets lokinet-bootstrap)
|
||||
endif()
|
||||
|
||||
foreach(exe ${exetargets})
|
||||
if(WIN32 AND NOT MSVC_VERSION)
|
||||
target_sources(${exe} PRIVATE ${CMAKE_BINARY_DIR}/${exe}.rc)
|
||||
|
@ -57,70 +55,18 @@ foreach(exe ${exetargets})
|
|||
endif()
|
||||
target_link_libraries(${exe} PUBLIC liblokinet)
|
||||
target_include_directories(${exe} PUBLIC "${PROJECT_SOURCE_DIR}")
|
||||
target_compile_definitions(${exe} PRIVATE -DVERSIONTAG=${GIT_VERSION_REAL})
|
||||
if(should_install)
|
||||
if(APPLE)
|
||||
install(TARGETS ${exe} BUNDLE DESTINATION "${PROJECT_BINARY_DIR}" COMPONENT lokinet)
|
||||
install(TARGETS ${exe}
|
||||
BUNDLE DESTINATION "${PROJECT_BINARY_DIR}"
|
||||
RUNTIME DESTINATION "."
|
||||
COMPONENT lokinet)
|
||||
else()
|
||||
install(TARGETS ${exe} RUNTIME DESTINATION bin COMPONENT lokinet)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(APPLE)
|
||||
|
||||
set(CODESIGN_APP "" CACHE STRING "codesign the macos app using this key identity")
|
||||
set(CODESIGN_APPEX "${CODESIGN_APP}" CACHE STRING "codesign the internal extension using this key identity; defaults to CODESIGN_APP if empty")
|
||||
|
||||
set(mac_icon ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns)
|
||||
add_custom_command(OUTPUT ${mac_icon}
|
||||
COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${mac_icon}
|
||||
DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh)
|
||||
add_custom_target(icons DEPENDS ${mac_icon})
|
||||
add_dependencies(lokinet icons lokinet-extension)
|
||||
add_custom_command(TARGET lokinet
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/bootstrap/mainnet.signed
|
||||
$<TARGET_BUNDLE_DIR:lokinet-extension>/Contents/Resources/bootstrap.signed
|
||||
COMMAND mkdir -p $<TARGET_BUNDLE_DIR:lokinet>/Contents/PlugIns
|
||||
COMMAND cp -a $<TARGET_BUNDLE_DIR:lokinet-extension> $<TARGET_BUNDLE_DIR:lokinet>/Contents/PlugIns/
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.provisionprofile
|
||||
$<TARGET_BUNDLE_DIR:lokinet>/Contents/embedded.provisionprofile
|
||||
)
|
||||
|
||||
set_target_properties(lokinet
|
||||
PROPERTIES
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "Lokinet"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${lokinet_VERSION}"
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "${lokinet_VERSION}"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "com.loki-project.lokinet"
|
||||
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/Info.plist.in"
|
||||
MACOSX_BUNDLE_ICON_FILE "${mac_icon}"
|
||||
MACOSX_BUNDLE_COPYRIGHT "© 2021, The Oxen Project")
|
||||
if (CODESIGN_APP AND CODESIGN_APPEX)
|
||||
message(STATUS "codesigning with ${CODESIGN_APP} (app) ${CODESIGN_APPEX} (appex)")
|
||||
set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/lokinet.app")
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in"
|
||||
"${PROJECT_BINARY_DIR}/sign.sh"
|
||||
@ONLY)
|
||||
add_custom_target(
|
||||
sign
|
||||
DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension
|
||||
COMMAND "${PROJECT_BINARY_DIR}/sign.sh"
|
||||
)
|
||||
else()
|
||||
message(WARNING "Not codesigning: CODESIGN_APP (=${CODESIGN_APP}) and/or CODESIGN_APPEX (=${CODESIGN_APPEX}) are not set")
|
||||
add_custom_target(
|
||||
sign
|
||||
DEPENDS lokinet lokinet-extension
|
||||
COMMAND "true")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SETCAP)
|
||||
install(CODE "execute_process(COMMAND ${SETCAP} cap_net_admin,cap_net_bind_service=+eip ${CMAKE_INSTALL_PREFIX}/bin/lokinet)")
|
||||
endif()
|
||||
|
|
|
@ -1,34 +1,83 @@
|
|||
import AppKit
|
||||
import Foundation
|
||||
import NetworkExtension
|
||||
import SystemExtensions
|
||||
|
||||
let app = NSApplication.shared
|
||||
|
||||
let START = "--start"
|
||||
let STOP = "--stop"
|
||||
|
||||
let HELP_STRING = "usage: lokinet {--start|--stop}"
|
||||
|
||||
class LokinetMain: NSObject, NSApplicationDelegate {
|
||||
var vpnManager = NETunnelProviderManager()
|
||||
let lokinetComponent = "com.loki-project.lokinet.network-extension"
|
||||
var mode = START
|
||||
let netextBundleId = "org.lokinet.network-extension"
|
||||
|
||||
func applicationDidFinishLaunching(_: Notification) {
|
||||
setupVPNJizz()
|
||||
if mode == START {
|
||||
startNetworkExtension()
|
||||
} else if mode == STOP {
|
||||
tearDownVPNTunnel()
|
||||
} else {
|
||||
result(msg: HELP_STRING)
|
||||
}
|
||||
}
|
||||
|
||||
func bail() {
|
||||
app.terminate(self)
|
||||
}
|
||||
|
||||
func setupVPNJizz() {
|
||||
NSLog("Starting up lokinet")
|
||||
func result(msg: String) {
|
||||
NSLog(msg)
|
||||
// TODO: does lokinet continue after this?
|
||||
bail()
|
||||
}
|
||||
|
||||
func tearDownVPNTunnel() {
|
||||
NSLog("Stopping Lokinet")
|
||||
NETunnelProviderManager.loadAllFromPreferences { [self] (savedManagers: [NETunnelProviderManager]?, error: Error?) in
|
||||
if let error = error {
|
||||
NSLog(error.localizedDescription)
|
||||
bail()
|
||||
self.result(msg: error.localizedDescription)
|
||||
return
|
||||
}
|
||||
|
||||
if let savedManagers = savedManagers {
|
||||
for manager in savedManagers {
|
||||
if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent {
|
||||
NSLog("%@", manager)
|
||||
if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.netextBundleId {
|
||||
manager.connection.stopVPNTunnel()
|
||||
self.result(msg: "Lokinet Down")
|
||||
}
|
||||
}
|
||||
}
|
||||
self.result(msg: "Lokinet is not up")
|
||||
}
|
||||
}
|
||||
|
||||
func startNetworkExtension() {
|
||||
#if MACOS_SYSTEM_EXTENSION
|
||||
NSLog("Loading Lokinet network extension")
|
||||
// Start by activating the system extension
|
||||
let activationRequest = OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: netextBundleId, queue: .main)
|
||||
activationRequest.delegate = self
|
||||
OSSystemExtensionManager.shared.submitRequest(activationRequest)
|
||||
#else
|
||||
setupVPNTunnel()
|
||||
#endif
|
||||
}
|
||||
|
||||
func setupVPNTunnel() {
|
||||
NSLog("Starting up Lokinet tunnel")
|
||||
NETunnelProviderManager.loadAllFromPreferences { [self] (savedManagers: [NETunnelProviderManager]?, error: Error?) in
|
||||
if let error = error {
|
||||
self.result(msg: error.localizedDescription)
|
||||
return
|
||||
}
|
||||
|
||||
if let savedManagers = savedManagers {
|
||||
for manager in savedManagers {
|
||||
if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.netextBundleId {
|
||||
NSLog("Found saved VPN Manager")
|
||||
self.vpnManager = manager
|
||||
}
|
||||
|
@ -37,7 +86,7 @@ class LokinetMain: NSObject, NSApplicationDelegate {
|
|||
let providerProtocol = NETunnelProviderProtocol()
|
||||
providerProtocol.serverAddress = "loki.loki" // Needs to be set to some non-null dummy value
|
||||
providerProtocol.username = "anonymous"
|
||||
providerProtocol.providerBundleIdentifier = self.lokinetComponent
|
||||
providerProtocol.providerBundleIdentifier = self.netextBundleId
|
||||
providerProtocol.enforceRoutes = true
|
||||
// macos seems to have trouble when this is true, and reports are that this breaks and
|
||||
// doesn't do what it says on the tin in the first place. Needs more testing.
|
||||
|
@ -46,28 +95,24 @@ class LokinetMain: NSObject, NSApplicationDelegate {
|
|||
self.vpnManager.isEnabled = true
|
||||
// self.vpnManager.isOnDemandEnabled = true
|
||||
self.vpnManager.localizedDescription = "lokinet"
|
||||
self.vpnManager.saveToPreferences(completionHandler: { error -> Void in
|
||||
self.vpnManager.saveToPreferences(completionHandler: { [self] error -> Void in
|
||||
if error != nil {
|
||||
NSLog("Error saving to preferences")
|
||||
NSLog(error!.localizedDescription)
|
||||
bail()
|
||||
self.result(msg: error!.localizedDescription)
|
||||
} else {
|
||||
self.vpnManager.loadFromPreferences(completionHandler: { error in
|
||||
if error != nil {
|
||||
NSLog("Error loading from preferences")
|
||||
NSLog(error!.localizedDescription)
|
||||
bail()
|
||||
self.result(msg: error!.localizedDescription)
|
||||
} else {
|
||||
do {
|
||||
NSLog("Trying to start")
|
||||
self.initializeConnectionObserver()
|
||||
try self.vpnManager.connection.startVPNTunnel()
|
||||
} catch let error as NSError {
|
||||
NSLog(error.localizedDescription)
|
||||
bail()
|
||||
self.result(msg: error.localizedDescription)
|
||||
} catch {
|
||||
NSLog("There was a fatal error")
|
||||
bail()
|
||||
self.result(msg: "There was a fatal error")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -77,11 +122,11 @@ class LokinetMain: NSObject, NSApplicationDelegate {
|
|||
}
|
||||
|
||||
func initializeConnectionObserver() {
|
||||
NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: vpnManager.connection, queue: OperationQueue.main) { _ -> Void in
|
||||
NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: vpnManager.connection, queue: OperationQueue.main) { [self] _ -> Void in
|
||||
if self.vpnManager.connection.status == .invalid {
|
||||
NSLog("VPN configuration is invalid")
|
||||
self.result(msg: "VPN configuration is invalid")
|
||||
} else if self.vpnManager.connection.status == .disconnected {
|
||||
NSLog("VPN is disconnected.")
|
||||
self.result(msg: "VPN is disconnected.")
|
||||
} else if self.vpnManager.connection.status == .connecting {
|
||||
NSLog("VPN is connecting...")
|
||||
} else if self.vpnManager.connection.status == .reasserting {
|
||||
|
@ -89,12 +134,102 @@ class LokinetMain: NSObject, NSApplicationDelegate {
|
|||
} else if self.vpnManager.connection.status == .disconnecting {
|
||||
NSLog("VPN is disconnecting...")
|
||||
} else if self.vpnManager.connection.status == .connected {
|
||||
NSLog("VPN Connected")
|
||||
self.result(msg: "VPN Connected")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let delegate = LokinetMain()
|
||||
app.delegate = delegate
|
||||
app.run()
|
||||
#if MACOS_SYSTEM_EXTENSION
|
||||
|
||||
extension LokinetMain: OSSystemExtensionRequestDelegate {
|
||||
func request(_: OSSystemExtensionRequest, didFinishWithResult result: OSSystemExtensionRequest.Result) {
|
||||
guard result == .completed else {
|
||||
NSLog("Unexpected result %d for system extension request", result.rawValue)
|
||||
return
|
||||
}
|
||||
NSLog("Lokinet system extension loaded")
|
||||
setupVPNTunnel()
|
||||
}
|
||||
|
||||
func request(_: OSSystemExtensionRequest, didFailWithError error: Error) {
|
||||
NSLog("System extension request failed: %@", error.localizedDescription)
|
||||
self.bail()
|
||||
}
|
||||
|
||||
func requestNeedsUserApproval(_ request: OSSystemExtensionRequest) {
|
||||
NSLog("Extension %@ requires user approval", request.identifier)
|
||||
}
|
||||
|
||||
func request(_ request: OSSystemExtensionRequest,
|
||||
actionForReplacingExtension existing: OSSystemExtensionProperties,
|
||||
withExtension extension: OSSystemExtensionProperties) -> OSSystemExtensionRequest.ReplacementAction
|
||||
{
|
||||
NSLog("Replacing extension %@ version %@ with version %@", request.identifier, existing.bundleShortVersion, `extension`.bundleShortVersion)
|
||||
return .replace
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
let args = CommandLine.arguments
|
||||
|
||||
// If we are invoked with no arguments then exec the gui. This is dumb, but there doesn't seem to
|
||||
// be a nicer way to do this on Apple's half-baked platform because:
|
||||
// - we have three "bundles" we need to manage: the GUI app, the system extension, and the Lokinet
|
||||
// app (this file) which loads the system extension.
|
||||
// - if we embed the system extension directly inside the GUI then it fails to launch because the
|
||||
// electron GUI's requirements (needed for JIT) conflict with the ability to load a system
|
||||
// extensions.
|
||||
// - if we embed Lokinet.app inside Lokinet-GUI.app and then the system extension inside Lokinet.app
|
||||
// then it works, but macos loses track of the system extension and doesn't remove it when you
|
||||
// remove the application. (It breaks your system, leaving an impossible-to-remove system
|
||||
// extension, in just the same way it breaks if you don't use Finder to remove the Application.
|
||||
// Apple used to say (around 2 years ago as of writing) that they would fix this situation "soon",
|
||||
// but hasn't, and has stopped saying anything about it.)
|
||||
// - if we try to use multiple executables (one to launch the system extension, one simple shell
|
||||
// script to execs the embedded GUI app) inside the Lokinet.app and make the GUI the default for
|
||||
// the application then Lokinet gets killed by gatekeeper because code signing only applies the
|
||||
// (required-for-system-extensions) provisioningprofile to the main binary in the app.
|
||||
//
|
||||
// So we are left needing *one* single binary that isn't the GUI but has to do double-duty for both
|
||||
// exec'ing the binary and loading lokinet, depending on how it is called.
|
||||
//
|
||||
// But of course there is no way to specify command-line arguments to the default binary macOS runs,
|
||||
// so we can't use a `--gui` flag or anything so abhorrent to macos purity, thus this nasty
|
||||
// solution:
|
||||
// - no args -- exec the GUI
|
||||
// - `--start` -- load the system extension and start lokinet
|
||||
// - `--stop` -- stop lokinet
|
||||
//
|
||||
// macOS: land of half-baked implementations and nasty hacks to make anything work.
|
||||
|
||||
if args.count == 1 {
|
||||
let gui_path = Bundle.main.resourcePath! + "/../Helpers/Lokinet-GUI.app"
|
||||
if !FileManager.default.fileExists(atPath: gui_path) {
|
||||
NSLog("Could not find gui app at %@", gui_path)
|
||||
exit(1)
|
||||
}
|
||||
let gui_url = URL(fileURLWithPath: gui_path, isDirectory: false)
|
||||
let gui_app_conf = NSWorkspace.OpenConfiguration()
|
||||
let group = DispatchGroup()
|
||||
group.enter()
|
||||
NSWorkspace.shared.openApplication(at: gui_url, configuration: gui_app_conf,
|
||||
completionHandler: { (app, error) in
|
||||
if error != nil {
|
||||
NSLog("Error launching gui: %@", error!.localizedDescription)
|
||||
} else {
|
||||
NSLog("Lauched GUI");
|
||||
}
|
||||
group.leave()
|
||||
})
|
||||
group.wait()
|
||||
|
||||
} else if args.count == 2 {
|
||||
let delegate = LokinetMain()
|
||||
delegate.mode = args[1]
|
||||
app.delegate = delegate
|
||||
app.run()
|
||||
} else {
|
||||
NSLog(HELP_STRING)
|
||||
}
|
||||
|
|
|
@ -1,73 +1,123 @@
|
|||
Codesigning and notarization on macOS
|
||||
If you are reading this to try to build Lokinet for yourself for an Apple operating system and
|
||||
simultaneously care about open source, privacy, or freedom then you, my friend, are a walking
|
||||
contradiction: you are trying to get Lokinet to work on a platform that actively despises open
|
||||
source, privacy, and freedom. Even Windows is a better choice in all of these categories than
|
||||
Apple.
|
||||
|
||||
This is painful. Thankfully most of the pain is now in CMake and a python script.
|
||||
This directory contains the magical incantations and random voodoo symbols needed to coax an Apple
|
||||
build. There's no reason builds have to be this stupid, except that Apple wants to funnel everyone
|
||||
into the no-CI, no-help, undocumented, non-toy-apps-need-not-apply modern Apple culture.
|
||||
|
||||
To build, codesign, and notarized and installer package, CMake needs to be invoked with:
|
||||
This is disgusting.
|
||||
|
||||
cd build
|
||||
rm -rf * # optional but recommended
|
||||
cmake .. -DBUILD_PACKAGE=ON -DDOWNLOAD_SODIUM=ON -DMACOS_SIGN_APP=ABC123... -DMACOS_SIGN_PKG=DEF456...
|
||||
But it gets worse.
|
||||
|
||||
where the ABC123... key is a "Developer ID Installer" key and PKG key is a "Developer ID
|
||||
Application" key. You have to go through a bunch of pain, pay Apple money, and then read a bunch of
|
||||
poorly written documentation that doesn't help very much to create these and get them working. But once you have them
|
||||
set up in Keychain, you should be able to list your keys with:
|
||||
The following two files, in particular, are the very worst manifestations of this already toxic
|
||||
Apple cancer: they are required for proper permissions to run on macOS, are undocumented, and can
|
||||
only be regenerated through the entirely closed source Apple Developer backend, for which you have
|
||||
to pay money first to get a team account (a personal account will not work), and they lock the
|
||||
resulting binaries to only run on individually selected Apple computers selected at the time the
|
||||
profile is provisioned (with no ability to allow it to run anywhere).
|
||||
|
||||
security find-identity -v
|
||||
lokinet.dev.provisionprofile
|
||||
lokinet-extension.dev.provisionprofile
|
||||
|
||||
and you should see (at least) one "Developer ID Installer: ..." and one "Developer ID Application:
|
||||
...". You need both for reasons that only Apple knows. The former is used to sign the installer
|
||||
.pkg, and the latter is used to sign everything *inside* the .pkg, and you can't use the same key
|
||||
for both because Apple designed code signing by marketing committee rather than ask any actual
|
||||
competent software developers how code signing should work.
|
||||
This is actively hostile to open source development, but that is nothing new for Apple.
|
||||
|
||||
Either way, these two values can be specified either by hex value or description string that
|
||||
`security find-identity -v` spits out.
|
||||
There are also release provisioning profiles
|
||||
|
||||
You also need to set up the notarization parameters; these can either be specified directly on the
|
||||
cmake command line by adding:
|
||||
lokinet.release.provisionprofile
|
||||
lokinet-extension.release.provisionprofile
|
||||
|
||||
-DMACOS_NOTARIZE_ASC=XYZ123 -DMACOS_NOTARIZE_USER=me@example.com -DMACOS_NOTARIZE_PASS=@keychain:codesigning-password
|
||||
These ones allow distribution of the app, but only if notarized, and again require notarization plus
|
||||
signing by a (paid) Apple developer account.
|
||||
|
||||
or, more simply, by putting them inside a `~/.notarization.cmake` file that will be included if it
|
||||
exists (and the MACOS_SIGN_* variables are set) -- see below.
|
||||
In order to make things work, you'll have to replace these provisioning profiles with your own
|
||||
(after paying Apple for the privilege of developing on their platform, of course) and change all the
|
||||
team/application/bundle IDs to reference your own team, matching the provisioning profiles. The dev
|
||||
provisioning profiles must be a "macOS Development" provisioning profile, and must include the
|
||||
signing keys and the authorized devices on which you want to run it. (The profiles bundled in this
|
||||
repository contains the lokinet team's "Apple Development" keys associated with the Oxen project,
|
||||
and mac dev boxes. This is *useless* for anyone else).
|
||||
|
||||
These three values here are:
|
||||
For release builds, you still need a provisioning profile, but it must be a "Distribution: Developer
|
||||
ID" provisioning profile, and are tied to a (paid) Developer ID. The ones in the repository are
|
||||
attached to the Oxen Project Developer ID and are useless to anyone else.
|
||||
|
||||
MACOS_NOTARIZE_ASC:
|
||||
Once you have that in place, you need to build and sign the package using a certificate matching
|
||||
your provisioning profile before your Apple system will allow it to run. (That's right, your $2000
|
||||
box won't let you run programs you build from source on it unless you also subscribe to a $100/year
|
||||
Apple developer account).
|
||||
|
||||
Organization-specific unique value; this is printed inside (brackets) when you run: `security
|
||||
find-identity -v`:
|
||||
Okay, so now that you have paid Apple more money for the privilege of using your own computer,
|
||||
here's how you make a signed lokinet app:
|
||||
|
||||
1) 1C75DDBF884DEF3D5927C3F29BB7FC5ADAE2E1B3 "Apple Development: me@example.com (ABC123XYZ9)"
|
||||
1) Decide which type of build you are doing: a lokinet system extension, or an app extension. The
|
||||
former must be signed and notarized and will only work when placed in the /Applications folder,
|
||||
but will not work as a dev build and cannot be distributed outside the Mac App Store. The latter
|
||||
is usable as a dev build, but still requires a signature and Apple-provided provisioningprofile
|
||||
listing the limited number of devices on which it is allowed to run.
|
||||
|
||||
MACOS_NOTARIZE_USER:
|
||||
For system extension builds you want to add the -DMACOS_SYSTEM_EXTENSION=ON flag to cmake.
|
||||
|
||||
Your Apple Developer login.
|
||||
2) Figure out the certificate to use for signing and make sure you have it installed. For a
|
||||
distributable system extension build you need a "Developer ID Application" key and certificate,
|
||||
issued by your paid developer.apple.com account. For dev builds you need a "Apple Development"
|
||||
certificate.
|
||||
|
||||
MACOS_NOTARIZE_PASS:
|
||||
In most cases you don't need to specify these; the default cmake script will figure them out.
|
||||
(If it can't, e.g. because you have multiple of the right type installed, it will error with the
|
||||
keys it found).
|
||||
|
||||
This should be an app-specific password created for signing on the Apple Developer website. You
|
||||
*can* specify it directly, but it is much better to use the magic `@keychain:blah` value, where
|
||||
'blah' is a password name recorded in Keychain. To get that in place you run:
|
||||
To be explicit, use `security find-identity -v` to list your keys, then list the key identity
|
||||
with -DCODESIGN_ID=.....
|
||||
|
||||
export HISTFILE='' # for bash: you don't want to store this in your history
|
||||
xcrun altool --store-password-in-keychain-item "NOTARIZE_PASSWORD" -u "user" -p "password"
|
||||
3) If you are doing a system extension build you will need to provide notarization login information by adding:
|
||||
|
||||
where NOTARIZE_PASSWORD is just some name for the password (I called it 'blah' or
|
||||
'codesigning-password' above), and the "user" and "password" are replaced with your actual Apple
|
||||
Developer account device-specific login credentials.
|
||||
-DMACOS_NOTARIZE_ASC=XYZ123 -DMACOS_NOTARIZE_USER=me@example.com -DMACOS_NOTARIZE_PASS=@keychain:codesigning-password
|
||||
|
||||
Optionally, put these last three inside a `~/.notarization.cmake` file:
|
||||
a) The first value (XYZ123) needs to be the organization-specific unique value, and is printed in
|
||||
brackets in the certificate description. For example:
|
||||
|
||||
set(MACOS_NOTARIZE_USER "jagerman@jagerman.com")
|
||||
set(MACOS_NOTARIZE_PASS "@keychain:codesigning-password")
|
||||
set(MACOS_NOTARIZE_ASC "SUQ8J2PCT7")
|
||||
15095CD1E6AF441ABC69BDC52EE186A18200A49F "Developer ID Application: Some Developer (ABC123XYZ9)"
|
||||
|
||||
Then, finally, you can build the package from the build directory with:
|
||||
would require ABC123XYZ9 for this field.
|
||||
|
||||
make package -j4 # or whatever -j makes you happy
|
||||
make notarize
|
||||
b) The USER field is your Apple Developer login e-mail address.
|
||||
|
||||
The former builds and signs the package, the latter submits it for notarization. This can take a
|
||||
few minutes; the script polls Apple's server until it is finished passing or failing notarization.
|
||||
c) The PASS field is a keychain reference holding your "Application-Specific Password". To set
|
||||
up such a password for your account, consult Apple documentation. Once you have it, load it
|
||||
into your keychain via:
|
||||
|
||||
export HISTFILE='' # Don't want to store this in the shell history
|
||||
xcrun altool --store-password-in-keychain-item "codesigning-password" -u "user" -p "password"
|
||||
|
||||
You can change "codesigning-password" to whatever you want (just make sure it agrees with the
|
||||
-DMACOS_NOTARIZE_PASS option you build with). "user" and "password" should be your developer
|
||||
account device-specific login credentials provided by Apple.
|
||||
|
||||
To make your life easier, stash these settings into a `~/.notarization.cmake` file inside your
|
||||
home directory; if you have not specified them in the build, and this file exists, lokinet's
|
||||
cmake will load it:
|
||||
|
||||
set(MACOS_NOTARIZE_USER "me@example.com")
|
||||
set(MACOS_NOTARIZE_PASS "@keychain:codesigning-password")
|
||||
set(MACOS_NOTARIZE_ASC "ABC123XYZ9")
|
||||
|
||||
4) Build and sign the package; there is a script `contrib/mac.sh` that can help (extra cmake options
|
||||
you need can be appended to the end), or you can build yourself in a build directory. See the
|
||||
script for the other cmake options that are typically needed. Note that `-G Ninja` (as well as a
|
||||
working ninja builder) are required.
|
||||
|
||||
If you get an error `errSecInternalComponent` this is Apple's highly descriptive way of telling
|
||||
you that you need to unlock your keychain, which you can do by running `security unlock`.
|
||||
|
||||
If doing it yourself, `ninja sign` will build and then sign the app.
|
||||
|
||||
If you need to also notarize (e.g. for a system extension build) run `./notarize.py` from the
|
||||
build directory (or alternatively `ninja notarize`, but the former gives you status output while
|
||||
it runs).
|
||||
|
||||
5) Packaging the app: you want to use `-DBUILD_PACKAGE=ON` when configuring with cmake and then,
|
||||
once all signing and notarization is complete, run `cpack` which will give you a .dmg and a .zip
|
||||
containing the release.
|
||||
|
|
|
@ -41,7 +41,7 @@ endif()
|
|||
|
||||
macro(system_or_submodule BIGNAME smallname pkgconf subdir)
|
||||
option(FORCE_${BIGNAME}_SUBMODULE "force using ${smallname} submodule" OFF)
|
||||
if(NOT STATIC AND NOT FORCE_${BIGNAME}_SUBMODULE)
|
||||
if(NOT BUILD_STATIC_DEPS AND NOT FORCE_${BIGNAME}_SUBMODULE AND NOT FORCE_ALL_SUBMODULES)
|
||||
pkg_check_modules(${BIGNAME} ${pkgconf} IMPORTED_TARGET)
|
||||
endif()
|
||||
if(${BIGNAME}_FOUND)
|
||||
|
@ -64,6 +64,7 @@ endmacro()
|
|||
system_or_submodule(OXENC oxenc liboxenc>=1.0.3 oxen-encoding)
|
||||
system_or_submodule(OXENMQ oxenmq liboxenmq>=1.2.12 oxen-mq)
|
||||
set(JSON_BuildTests OFF CACHE INTERNAL "")
|
||||
set(JSON_Install OFF CACHE INTERNAL "")
|
||||
system_or_submodule(NLOHMANN nlohmann_json nlohmann_json>=3.7.0 nlohmann)
|
||||
|
||||
if (STATIC OR FORCE_SPDLOG_SUBMODULE OR FORCE_FMT_SUBMODULE)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit abcd94814e261ffd88104357e3946201d0d2c8e0
|
|
@ -205,6 +205,11 @@ 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)
|
||||
|
@ -227,7 +232,6 @@ target_link_libraries(liblokinet PUBLIC
|
|||
lokinet-platform
|
||||
lokinet-util
|
||||
lokinet-cryptography
|
||||
sqlite_orm
|
||||
ngtcp2_static
|
||||
oxenmq::oxenmq)
|
||||
target_link_libraries(liblokinet PRIVATE libunbound)
|
||||
|
@ -252,7 +256,7 @@ if(BUILD_LIBLOKINET)
|
|||
if(WIN32)
|
||||
target_link_libraries(lokinet-shared PUBLIC ws2_32 iphlpapi -fstack-protector)
|
||||
install(TARGETS lokinet-shared DESTINATION bin COMPONENT liblokinet)
|
||||
else()
|
||||
elseif(NOT APPLE)
|
||||
install(TARGETS lokinet-shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT liblokinet)
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
if (BUILD_SHARED_LIBS OR NOT BUILD_STATIC_DEPS OR NOT STATIC_LINK)
|
||||
message(FATAL_ERROR "macOS builds require a full static build; perhaps use the contrib/macos.sh script to build?")
|
||||
message(FATAL_ERROR "macOS builds require a full static build; perhaps use the contrib/mac.sh script to build?")
|
||||
endif()
|
||||
|
||||
# god (steve jobs) made apple so that man may suffer
|
||||
|
@ -25,26 +25,37 @@ target_link_libraries(lokinet-extension PRIVATE
|
|||
${COREFOUNDATION}
|
||||
${NETEXT})
|
||||
|
||||
# Not sure what -fapplication-extension does, but XCode puts it in so...
|
||||
# -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.
|
||||
target_compile_options(lokinet-extension PRIVATE -fapplication-extension -fobjc-arc)
|
||||
target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain)
|
||||
target_compile_options(lokinet-extension PRIVATE -fobjc-arc)
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
target_compile_definitions(lokinet-extension PRIVATE MACOS_SYSTEM_EXTENSION)
|
||||
target_compile_definitions(lokinet-util PUBLIC MACOS_SYSTEM_EXTENSION)
|
||||
else()
|
||||
target_link_options(lokinet-extension PRIVATE -e _NSExtensionMain)
|
||||
endif()
|
||||
|
||||
target_link_libraries(lokinet-extension PUBLIC
|
||||
liblokinet
|
||||
${COREFOUNDATION}
|
||||
${NETEXT})
|
||||
if(MACOS_SYSTEM_EXTENSION)
|
||||
set(bundle_ext systemextension)
|
||||
set(product_type com.apple.product-type.system-extension)
|
||||
else()
|
||||
set(bundle_ext appex)
|
||||
set(product_type com.apple.product-type.app-extension)
|
||||
endif()
|
||||
|
||||
set_target_properties(lokinet-extension PROPERTIES
|
||||
BUNDLE TRUE
|
||||
BUNDLE_EXTENSION appex
|
||||
MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in
|
||||
XCODE_PRODUCT_TYPE com.apple.product-type.app-extension
|
||||
BUNDLE_EXTENSION ${bundle_ext}
|
||||
OUTPUT_NAME org.lokinet.network-extension
|
||||
MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.Info.plist.in
|
||||
XCODE_PRODUCT_TYPE ${product_type}
|
||||
)
|
||||
|
||||
add_custom_command(TARGET lokinet-extension
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.provisionprofile
|
||||
$<TARGET_BUNDLE_DIR:lokinet-extension>/Contents/embedded.provisionprofile
|
||||
if(CODESIGN AND CODESIGN_EXT_PROFILE)
|
||||
add_custom_command(TARGET lokinet-extension
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CODESIGN_EXT_PROFILE}
|
||||
$<TARGET_BUNDLE_DIR:lokinet-extension>/Contents/embedded.provisionprofile
|
||||
)
|
||||
endif()
|
||||
|
|
|
@ -5,18 +5,19 @@
|
|||
extern NSString* error_domain;
|
||||
|
||||
/**
|
||||
* "Trampoline" class that listens for UDP DNS packets on port 1053 coming from lokinet's embedded
|
||||
* libunbound (when exit mode is enabled), wraps them via NetworkExtension's crappy UDP API, then
|
||||
* sends responses back to libunbound to be parsed/etc. This class knows nothing about DNS, it is
|
||||
* basically just a UDP packet forwarder.
|
||||
* "Trampoline" class that listens for UDP DNS packets when we have exit mode enabled. These arrive
|
||||
* on localhost:1053 coming from lokinet's embedded libunbound (when exit mode is enabled), wraps
|
||||
* them via NetworkExtension's crappy UDP API, then sends responses back to libunbound to be
|
||||
* parsed/etc. This class knows nothing about DNS, it is basically just a UDP packet forwarder, but
|
||||
* using Apple magic reinvented wheel wrappers that are oh so wonderful like everything Apple.
|
||||
*
|
||||
* So for a lokinet configuration of "upstream=1.1.1.1", when exit mode is OFF:
|
||||
* - DNS requests go to TUNNELIP:53, get sent to libunbound, which forwards them (directly) to the
|
||||
* upstream DNS server(s).
|
||||
* - DNS requests go unbound either to 127.0.0.1:53 directly (system extension) or bounced through
|
||||
* TUNNELIP:53 (app extension), which forwards them (directly) to the upstream DNS server(s).
|
||||
* With exit mode ON:
|
||||
* - DNS requests go to TUNNELIP:53, get send to libunbound, which forwards them to 127.0.0.1:1053,
|
||||
* which encapsulates them in Apple's god awful crap, then (on a response) sends them back to
|
||||
* libunbound.
|
||||
* - DNS requests go to unbound, as above, and unbound forwards them to 127.0.0.1:1053, which
|
||||
* encapsulates them in Apple's god awful crap, then (on a response) sends them back to
|
||||
* libunbound to be delivered back to the requestor.
|
||||
* (This assumes a non-lokinet DNS; .loki and .snode get handled before either of these).
|
||||
*/
|
||||
@interface LLARPDNSTrampoline : NSObject
|
||||
|
@ -40,6 +41,7 @@ extern NSString* error_domain;
|
|||
uv_async_t write_trigger;
|
||||
}
|
||||
- (void)startWithUpstreamDns:(NWUDPSession*)dns
|
||||
listenIp:(NSString*)listenIp
|
||||
listenPort:(uint16_t)listenPort
|
||||
uvLoop:(uv_loop_t*)loop
|
||||
completionHandler:(void (^)(NSError* error))completionHandler;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "DNSTrampoline.h"
|
||||
#include <uv.h>
|
||||
|
||||
NSString* error_domain = @"com.loki-project.lokinet";
|
||||
NSString* error_domain = @"org.lokinet";
|
||||
|
||||
|
||||
// Receiving an incoming packet, presumably from libunbound. NB: this is called from the libuv
|
||||
|
@ -68,10 +68,12 @@ static void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* b
|
|||
@implementation LLARPDNSTrampoline
|
||||
|
||||
- (void)startWithUpstreamDns:(NWUDPSession*) dns
|
||||
listenIp:(NSString*) listenIp
|
||||
listenPort:(uint16_t) listenPort
|
||||
uvLoop:(uv_loop_t*) loop
|
||||
completionHandler:(void (^)(NSError* error))completionHandler
|
||||
{
|
||||
NSLog(@"Setting up trampoline");
|
||||
pending_writes = [[NSMutableArray<NSData*> alloc] init];
|
||||
write_trigger.data = (__bridge void*) self;
|
||||
uv_async_init(loop, &write_trigger, write_flusher);
|
||||
|
@ -79,7 +81,7 @@ static void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* b
|
|||
request_socket.data = (__bridge void*) self;
|
||||
uv_udp_init(loop, &request_socket);
|
||||
struct sockaddr_in recv_addr;
|
||||
uv_ip4_addr("127.0.0.1", listenPort, &recv_addr);
|
||||
uv_ip4_addr(listenIp.UTF8String, listenPort, &recv_addr);
|
||||
int ret = uv_udp_bind(&request_socket, (const struct sockaddr*) &recv_addr, UV_UDP_REUSEADDR);
|
||||
if (ret < 0) {
|
||||
NSString* errstr = [NSString stringWithFormat:@"Failed to start DNS trampoline: %s", uv_strerror(ret)];
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
#include "context_wrapper.h"
|
||||
#include "DNSTrampoline.h"
|
||||
|
||||
#define LLARP_APPLE_PACKET_BUF_SIZE 64
|
||||
|
||||
@interface LLARPPacketTunnel : NEPacketTunnelProvider
|
||||
{
|
||||
void* lokinet;
|
||||
llarp_incoming_packet packet_buf[LLARP_APPLE_PACKET_BUF_SIZE];
|
||||
@public NEPacketTunnelNetworkSettings* settings;
|
||||
@public NEIPv4Route* tun_route4;
|
||||
@public NEIPv6Route* tun_route6;
|
||||
|
@ -35,8 +38,8 @@ static void packet_writer(int af, const void* data, size_t size, void* ctx) {
|
|||
|
||||
NSData* buf = [NSData dataWithBytesNoCopy:(void*)data length:size freeWhenDone:NO];
|
||||
LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx;
|
||||
NEPacket* packet = [[NEPacket alloc] initWithData:buf protocolFamily: af];
|
||||
[t.packetFlow writePacketObjects:@[packet]];
|
||||
[t.packetFlow writePackets:@[buf]
|
||||
withProtocols:@[[NSNumber numberWithInt:af]]];
|
||||
}
|
||||
|
||||
static void start_packet_reader(void* ctx) {
|
||||
|
@ -48,6 +51,7 @@ static void start_packet_reader(void* ctx) {
|
|||
}
|
||||
|
||||
static void add_ipv4_route(const char* addr, const char* netmask, void* ctx) {
|
||||
NSLog(@"Adding IPv4 route %s:%s to packet tunnel", addr, netmask);
|
||||
NEIPv4Route* route = [[NEIPv4Route alloc]
|
||||
initWithDestinationAddress: [NSString stringWithUTF8String:addr]
|
||||
subnetMask: [NSString stringWithUTF8String:netmask]];
|
||||
|
@ -65,6 +69,7 @@ static void add_ipv4_route(const char* addr, const char* netmask, void* ctx) {
|
|||
}
|
||||
|
||||
static void del_ipv4_route(const char* addr, const char* netmask, void* ctx) {
|
||||
NSLog(@"Removing IPv4 route %s:%s to packet tunnel", addr, netmask);
|
||||
NEIPv4Route* route = [[NEIPv4Route alloc]
|
||||
initWithDestinationAddress: [NSString stringWithUTF8String:addr]
|
||||
subnetMask: [NSString stringWithUTF8String:netmask]];
|
||||
|
@ -124,6 +129,7 @@ static void del_ipv6_route(const char* addr, int prefix, void* ctx) {
|
|||
}
|
||||
|
||||
static void add_default_route(void* ctx) {
|
||||
NSLog(@"Making the tunnel the default route");
|
||||
LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx;
|
||||
|
||||
t->settings.IPv4Settings.includedRoutes = @[NEIPv4Route.defaultRoute];
|
||||
|
@ -133,6 +139,7 @@ static void add_default_route(void* ctx) {
|
|||
}
|
||||
|
||||
static void del_default_route(void* ctx) {
|
||||
NSLog(@"Removing default route from tunnel");
|
||||
LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx;
|
||||
|
||||
t->settings.IPv4Settings.includedRoutes = @[t->tun_route4];
|
||||
|
@ -148,9 +155,21 @@ static void del_default_route(void* ctx) {
|
|||
[self.packetFlow readPacketObjectsWithCompletionHandler: ^(NSArray<NEPacket*>* packets) {
|
||||
if (lokinet == nil)
|
||||
return;
|
||||
|
||||
size_t size = 0;
|
||||
for (NEPacket* p in packets) {
|
||||
llarp_apple_incoming(lokinet, p.data.bytes, p.data.length);
|
||||
packet_buf[size].bytes = p.data.bytes;
|
||||
packet_buf[size].size = p.data.length;
|
||||
size++;
|
||||
if (size >= LLARP_APPLE_PACKET_BUF_SIZE)
|
||||
{
|
||||
llarp_apple_incoming(lokinet, packet_buf, size);
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
if (size > 0)
|
||||
llarp_apple_incoming(lokinet, packet_buf, size);
|
||||
|
||||
[self readPackets];
|
||||
}];
|
||||
}
|
||||
|
@ -190,7 +209,14 @@ static void del_default_route(void* ctx) {
|
|||
// We don't have a fixed address so just stick some bogus value here:
|
||||
settings = [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.3.2.1"];
|
||||
|
||||
NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[ip]];
|
||||
#ifdef MACOS_SYSTEM_EXTENSION
|
||||
NSString* dns_ip = [NSString stringWithUTF8String:conf.dns_bind_ip];
|
||||
#else
|
||||
// TODO: placeholder
|
||||
NSString* dns_ip = ip;
|
||||
#endif
|
||||
NSLog(@"setting dns to %@", dns_ip);
|
||||
NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[dns_ip]];
|
||||
dns.domainName = @"localhost.loki";
|
||||
dns.matchDomains = @[@""];
|
||||
// In theory, matchDomains is supposed to be set to DNS suffixes that we resolve. This seems
|
||||
|
@ -246,11 +272,13 @@ static void del_default_route(void* ctx) {
|
|||
return completionHandler(start_failure);
|
||||
}
|
||||
|
||||
NSLog(@"Starting DNS exit mode trampoline to %@ on 127.0.0.1:%d", upstreamdns_ep, dns_trampoline_port);
|
||||
NSString* dns_tramp_ip = @"127.0.0.1";
|
||||
NSLog(@"Starting DNS exit mode trampoline to %@ on %@:%d", upstreamdns_ep, dns_tramp_ip, dns_trampoline_port);
|
||||
NWUDPSession* upstreamdns = [strongSelf createUDPSessionThroughTunnelToEndpoint:upstreamdns_ep fromEndpoint:nil];
|
||||
strongSelf->dns_tramp = [LLARPDNSTrampoline alloc];
|
||||
[strongSelf->dns_tramp
|
||||
startWithUpstreamDns:upstreamdns
|
||||
listenIp:dns_tramp_ip
|
||||
listenPort:dns_trampoline_port
|
||||
uvLoop:llarp_apple_get_uv_loop(strongSelf->lokinet)
|
||||
completionHandler:^(NSError* error) {
|
||||
|
@ -258,7 +286,7 @@ static void del_default_route(void* ctx) {
|
|||
NSLog(@"Error starting dns trampoline: %@", error);
|
||||
return completionHandler(error);
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)stopTunnelWithReason:(NEProviderStopReason)reason
|
||||
|
@ -308,3 +336,12 @@ static void del_default_route(void* ctx) {
|
|||
}
|
||||
|
||||
@end
|
||||
|
||||
#ifdef MACOS_SYSTEM_EXTENSION
|
||||
|
||||
int main() {
|
||||
[NEProvider startSystemExtensionMode];
|
||||
dispatch_main();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <cassert>
|
||||
#include <llarp/net/ip_packet.hpp>
|
||||
#include <llarp/config/config.hpp>
|
||||
#include <llarp/constants/apple.hpp>
|
||||
#include <llarp/util/fs.hpp>
|
||||
#include <uvw/loop.h>
|
||||
#include <llarp/util/logging.hpp>
|
||||
|
@ -14,10 +15,6 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
// The default 127.0.0.1:53 won't work (because we run unprivileged) so remap it to this (unless
|
||||
// specifically overridden to something else in the config):
|
||||
const llarp::SockAddr DefaultDNSBind{"127.0.0.1:1153"};
|
||||
|
||||
struct instance_data
|
||||
{
|
||||
llarp::apple::Context context;
|
||||
|
@ -30,7 +27,8 @@ namespace
|
|||
|
||||
} // namespace
|
||||
|
||||
const uint16_t dns_trampoline_port = 1053;
|
||||
// Expose this with C linkage so that objective-c can use it
|
||||
extern "C" const uint16_t dns_trampoline_port = llarp::apple::dns_trampoline_port;
|
||||
|
||||
void*
|
||||
llarp_apple_init(llarp_apple_config* appleconf)
|
||||
|
@ -89,10 +87,12 @@ llarp_apple_init(llarp_apple_config* appleconf)
|
|||
}
|
||||
}
|
||||
|
||||
// The default DNS bind setting just isn't something we can use as a non-root network extension
|
||||
// so remap the default value to a high port unless explicitly set to something else.
|
||||
if (config->dns.m_bind == llarp::SockAddr{"127.0.0.1:53"})
|
||||
config->dns.m_bind = DefaultDNSBind;
|
||||
#ifdef MACOS_SYSTEM_EXTENSION
|
||||
std::strncpy(
|
||||
appleconf->dns_bind_ip,
|
||||
config->dns.m_bind.hostString().c_str(),
|
||||
sizeof(appleconf->dns_bind_ip));
|
||||
#endif
|
||||
|
||||
// If no explicit bootstrap then set the system default one included with the app bundle
|
||||
if (config->bootstrap.files.empty())
|
||||
|
@ -170,20 +170,26 @@ llarp_apple_get_uv_loop(void* lokinet)
|
|||
}
|
||||
|
||||
int
|
||||
llarp_apple_incoming(void* lokinet, const void* bytes, size_t size)
|
||||
llarp_apple_incoming(void* lokinet, const llarp_incoming_packet* packets, size_t size)
|
||||
{
|
||||
auto& inst = *static_cast<instance_data*>(lokinet);
|
||||
|
||||
auto iface = inst.iface.lock();
|
||||
if (!iface)
|
||||
return -2;
|
||||
return -1;
|
||||
|
||||
llarp_buffer_t buf{static_cast<const uint8_t*>(bytes), size};
|
||||
if (iface->OfferReadPacket(buf))
|
||||
return 0;
|
||||
int count = 0;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
llarp_buffer_t buf{static_cast<const uint8_t*>(packets[i].bytes), packets[i].size};
|
||||
if (iface->OfferReadPacket(buf))
|
||||
count++;
|
||||
else
|
||||
llarp::LogError("invalid IP packet: ", llarp::buffer_printer(buf));
|
||||
}
|
||||
|
||||
llarp::LogError("invalid IP packet: ", llarp::buffer_printer(buf));
|
||||
return -1;
|
||||
iface->MaybeWakeUpperLayers();
|
||||
return count;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -82,6 +82,12 @@ extern "C"
|
|||
char upstream_dns[INET_ADDRSTRLEN];
|
||||
uint16_t upstream_dns_port;
|
||||
|
||||
#ifdef MACOS_SYSTEM_EXTENSION
|
||||
/// DNS bind IP; llarp_apple_init writes the lokinet config value here so that we know (in Apple
|
||||
/// API code) what to set DNS to when lokinet gets turned on. Null terminated.
|
||||
char dns_bind_ip[INET_ADDRSTRLEN];
|
||||
#endif
|
||||
|
||||
/// \defgroup callbacks Callbacks
|
||||
/// Callbacks we invoke for various operations that require glue into the Apple network
|
||||
/// extension APIs. All of these except for ns_logger are passed the pointer provided to
|
||||
|
@ -135,12 +141,23 @@ extern "C"
|
|||
uv_loop_t*
|
||||
llarp_apple_get_uv_loop(void* lokinet);
|
||||
|
||||
/// Called to deliver an incoming packet from the apple layer into lokinet; returns 0 on success,
|
||||
/// -1 if the packet could not be parsed, -2 if there is no current active VPNInterface associated
|
||||
/// with the lokinet (which generally means llarp_apple_start wasn't called or failed, or lokinet
|
||||
/// is in the process of shutting down).
|
||||
/// Struct of packet data; a C array of tests gets passed to llarp_apple_incoming
|
||||
typedef struct llarp_incoming_packet
|
||||
{
|
||||
const void* bytes;
|
||||
size_t size;
|
||||
} llarp_incoming_packet;
|
||||
|
||||
/// Called to deliver one or more incoming packets from the apple layer into lokinet. Takes a C
|
||||
/// array of `llarp_incoming_packets` with pointers/sizes set to the individual new packets that
|
||||
/// have arrived.
|
||||
///
|
||||
/// Returns the number of valid packets on success (which can be less than the number of provided
|
||||
/// packets, if some failed to parse), or -1 if there is no current active VPNInterface associated
|
||||
/// with the lokinet instance (which generally means llarp_apple_start wasn't called or failed, or
|
||||
/// lokinet is in the process of shutting down).
|
||||
int
|
||||
llarp_apple_incoming(void* lokinet, const void* bytes, size_t size);
|
||||
llarp_apple_incoming(void* lokinet, const llarp_incoming_packet* packets, size_t size);
|
||||
|
||||
/// Stops a lokinet instance created with `llarp_apple_initialize`. This waits for lokinet to
|
||||
/// shut down and rejoins the thread. After this call the given pointer is no longer valid.
|
||||
|
|
|
@ -775,11 +775,7 @@ namespace llarp
|
|||
// Most non-linux platforms have loopback as 127.0.0.1/32, but linux uses 127.0.0.1/8 so that we
|
||||
// can bind to other 127.* IPs to avoid conflicting with something else that may be listening on
|
||||
// 127.0.0.1:53.
|
||||
#ifdef __linux__
|
||||
constexpr Default DefaultDNSBind{"127.3.2.1:53"};
|
||||
#else
|
||||
constexpr Default DefaultDNSBind{"127.0.0.1:53"};
|
||||
#endif
|
||||
constexpr Default DefaultDNSBind{platform::is_linux ? "127.3.2.1:53" : "127.0.0.1:53"};
|
||||
|
||||
// Default, but if we get any upstream (including upstream=, i.e. empty string) we clear it
|
||||
constexpr Default DefaultUpstreamDNS{"9.9.9.10"};
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace llarp::apple
|
||||
{
|
||||
/// Localhost port on macOS where we proxy DNS requests *through* the tunnel, because without
|
||||
/// calling into special snowflake Apple network APIs an extension's network connections all go
|
||||
/// around the tunnel, even when the tunnel is (supposedly) the default route.
|
||||
inline constexpr std::uint16_t dns_trampoline_port = 1053;
|
||||
|
||||
/// We query the above trampoline from unbound with this fixed source port (so that the trampoline
|
||||
/// is simplified by not having to track different ports for different requests).
|
||||
inline constexpr std::uint16_t dns_trampoline_source_port = 1054;
|
||||
} // namespace llarp::apple
|
|
@ -32,7 +32,7 @@ namespace llarp::platform
|
|||
|
||||
/// are we an apple platform ?
|
||||
inline constexpr bool is_apple =
|
||||
#ifdef __apple__
|
||||
#ifdef __APPLE__
|
||||
true
|
||||
#else
|
||||
false
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "unbound_resolver.hpp"
|
||||
|
||||
#include "server.hpp"
|
||||
#include <llarp/constants/apple.hpp>
|
||||
#include <llarp/constants/platform.hpp>
|
||||
#include <llarp/util/buffer.hpp>
|
||||
#include <sstream>
|
||||
#include <llarp/util/str.hpp>
|
||||
|
@ -144,37 +146,51 @@ namespace llarp::dns
|
|||
bool
|
||||
UnboundResolver::AddUpstreamResolver(const SockAddr& upstreamResolver)
|
||||
{
|
||||
std::stringstream ss;
|
||||
auto hoststr = upstreamResolver.hostString();
|
||||
ss << hoststr;
|
||||
const auto hoststr = upstreamResolver.hostString();
|
||||
std::string upstream = hoststr;
|
||||
|
||||
if (const auto port = upstreamResolver.getPort(); port != 53)
|
||||
ss << "@" << port;
|
||||
const auto port = upstreamResolver.getPort();
|
||||
if (port != 53)
|
||||
{
|
||||
upstream += '@';
|
||||
upstream += std::to_string(port);
|
||||
}
|
||||
|
||||
const auto str = ss.str();
|
||||
if (ub_ctx_set_fwd(unboundContext, str.c_str()) != 0)
|
||||
LogError("Adding upstream resolver ", upstream);
|
||||
if (ub_ctx_set_fwd(unboundContext, upstream.c_str()) != 0)
|
||||
{
|
||||
Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
#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 tunnel using
|
||||
// normal sockets but instead we "get" to use Apple's interfaces, hurray).
|
||||
if (hoststr == "127.0.0.1")
|
||||
if constexpr (platform::is_apple)
|
||||
{
|
||||
// Not at all clear why this is needed but without it we get "send failed: Can't assign
|
||||
// requested address" when unbound tries to connect to the localhost address using a source
|
||||
// address of 0.0.0.0. Yay apple.
|
||||
ub_ctx_set_option(unboundContext, "outgoing-interface:", hoststr.c_str());
|
||||
// On Apple, when we turn on exit mode, we can't directly connect to upstream from here
|
||||
// because, from within the network extension, macOS ignores setting the tunnel as the default
|
||||
// route and would leak all DNS; instead we have to bounce things through the objective C
|
||||
// trampoline code so that it can call into Apple's special snowflake API to set up a socket
|
||||
// that has the magic Apple snowflake sauce added on top so that it actually routes through
|
||||
// the tunnel instead of around it.
|
||||
//
|
||||
// This behaviour is all carefully and explicitly documented by Apple with plenty of examples
|
||||
// and other exposition, of course, just like all of their wonderful new APIs to reinvent
|
||||
// standard unix interfaces.
|
||||
if (hoststr == "127.0.0.1" && port == apple::dns_trampoline_port)
|
||||
{
|
||||
// Not at all clear why this is needed but without it we get "send failed: Can't assign
|
||||
// requested address" when unbound tries to connect to the localhost address using a source
|
||||
// address of 0.0.0.0. Yay apple.
|
||||
ub_ctx_set_option(unboundContext, "outgoing-interface:", "127.0.0.1");
|
||||
|
||||
// The trampoline expects just a single source port (and sends everything back to it)
|
||||
ub_ctx_set_option(unboundContext, "outgoing-range:", "1");
|
||||
ub_ctx_set_option(unboundContext, "outgoing-port-avoid:", "0-65535");
|
||||
ub_ctx_set_option(unboundContext, "outgoing-port-permit:", "1253");
|
||||
// The trampoline expects just a single source port (and sends everything back to it)
|
||||
ub_ctx_set_option(unboundContext, "outgoing-range:", "1");
|
||||
ub_ctx_set_option(unboundContext, "outgoing-port-avoid:", "0-65535");
|
||||
ub_ctx_set_option(
|
||||
unboundContext,
|
||||
"outgoing-port-permit:",
|
||||
std::to_string(apple::dns_trampoline_source_port).c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <llarp/rpc/endpoint_rpc.hpp>
|
||||
#include <llarp/util/str.hpp>
|
||||
#include <llarp/dns/srv_data.hpp>
|
||||
#include <llarp/constants/platform.hpp>
|
||||
|
||||
#include <oxenc/bt.h>
|
||||
|
||||
|
@ -71,9 +72,10 @@ namespace llarp
|
|||
#ifdef __APPLE__
|
||||
// DNS on Apple is a bit weird because in order for the NetworkExtension itself to send data
|
||||
// through the tunnel we have to proxy DNS requests through Apple APIs (and so our actual
|
||||
// upstream DNS won't be set in our resolvers, which is why the vanilla IsUpstreamResolver
|
||||
// won't work for us. However when active the mac also only queries the main tunnel IP for
|
||||
// DNS, so we consider anything else to be upstream-bound DNS to let it through the tunnel.
|
||||
// upstream DNS won't be set in our resolvers, which is why the vanilla IsUpstreamResolver,
|
||||
// above, won't work for us). However when active the mac also only queries the main tunnel
|
||||
// IP for DNS, so we consider anything else to be upstream-bound DNS to let it through the
|
||||
// tunnel.
|
||||
bool
|
||||
IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const override
|
||||
{
|
||||
|
@ -87,7 +89,7 @@ namespace llarp
|
|||
{
|
||||
m_PacketRouter = std::make_unique<vpn::PacketRouter>(
|
||||
[this](net::IPPacket pkt) { HandleGotUserPacket(std::move(pkt)); });
|
||||
#if defined(ANDROID) || defined(__APPLE__)
|
||||
#if defined(ANDROID) || (defined(__APPLE__) && !defined(MACOS_SYSTEM_EXTENSION))
|
||||
m_Resolver = std::make_shared<DnsInterceptor>(r, this);
|
||||
m_PacketRouter->AddUDPHandler(huint16_t{53}, [&](net::IPPacket pkt) {
|
||||
const size_t ip_header_size = (pkt.Header()->ihl * 4);
|
||||
|
@ -1066,6 +1068,15 @@ namespace llarp
|
|||
src = pkt.srcv6();
|
||||
}
|
||||
|
||||
if constexpr (llarp::platform::is_apple)
|
||||
{
|
||||
if (dst == m_OurIP)
|
||||
{
|
||||
HandleWriteIPPacket(pkt.ConstBuffer(), src, dst, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_state->m_ExitEnabled)
|
||||
{
|
||||
dst = net::ExpandV4(net::TruncateV6(dst));
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
namespace llarp
|
||||
{
|
||||
#ifdef LOKINET_PEERSTATS_BACKEND
|
||||
|
||||
PeerDb::PeerDb()
|
||||
{
|
||||
m_lastFlush.store({});
|
||||
|
@ -297,4 +299,66 @@ namespace llarp
|
|||
return obj;
|
||||
}
|
||||
|
||||
#else // !LOKINET_PEERSTATS
|
||||
|
||||
// Empty stubs
|
||||
|
||||
PeerDb::PeerDb()
|
||||
{
|
||||
throw std::logic_error{"Peer stats backend not enabled!"};
|
||||
}
|
||||
|
||||
void PeerDb::loadDatabase(std::optional<fs::path>)
|
||||
{}
|
||||
|
||||
void
|
||||
PeerDb::flushDatabase()
|
||||
{}
|
||||
|
||||
void
|
||||
PeerDb::accumulatePeerStats(const RouterID&, const PeerStats&)
|
||||
{}
|
||||
|
||||
void
|
||||
PeerDb::modifyPeerStats(const RouterID&, std::function<void(PeerStats&)>)
|
||||
{}
|
||||
|
||||
std::optional<PeerStats>
|
||||
PeerDb::getCurrentPeerStats(const RouterID&) const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<PeerStats>
|
||||
PeerDb::listAllPeerStats() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<PeerStats>
|
||||
PeerDb::listPeerStats(const std::vector<RouterID>&) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
PeerDb::handleGossipedRC(const RouterContact&, llarp_time_t)
|
||||
{}
|
||||
|
||||
void
|
||||
PeerDb::configure(const RouterConfig& routerConfig)
|
||||
{}
|
||||
|
||||
bool
|
||||
PeerDb::shouldFlush(llarp_time_t now)
|
||||
{}
|
||||
|
||||
util::StatusObject
|
||||
PeerDb::ExtractStatus() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}; // namespace llarp
|
||||
|
|
|
@ -4,14 +4,15 @@
|
|||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <sqlite_orm/sqlite_orm.h>
|
||||
|
||||
#include <llarp/util/fs.hpp>
|
||||
#include <llarp/config/config.hpp>
|
||||
#include <llarp/router_id.hpp>
|
||||
#include <llarp/util/time.hpp>
|
||||
#include <llarp/util/status.hpp>
|
||||
#include "types.hpp"
|
||||
#ifdef LOKINET_PEERSTATS_BACKEND
|
||||
#include "orm.hpp"
|
||||
#endif
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
@ -126,6 +127,7 @@ namespace llarp
|
|||
util::StatusObject
|
||||
ExtractStatus() const;
|
||||
|
||||
#ifdef LOKINET_PEERSTATS_BACKEND
|
||||
private:
|
||||
std::unordered_map<RouterID, PeerStats> m_peerStats;
|
||||
mutable std::mutex m_statsLock;
|
||||
|
@ -133,6 +135,7 @@ namespace llarp
|
|||
std::unique_ptr<PeerDbStorage> m_storage;
|
||||
|
||||
std::atomic<llarp_time_t> m_lastFlush;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace llarp
|
||||
|
|
|
@ -93,9 +93,9 @@ build 1 or many cross targets:
|
|||
|
||||
### MacOS <span id="mac-install" />
|
||||
|
||||
Lokinet ~~is~~ will be available on the Apple App store.
|
||||
Source code compilation of Lokinet by end users is not supported or permitted by apple on their platforms, see [this](contrib/macos/README.txt) for more information.
|
||||
|
||||
Source code compilation of Lokinet by end users is not supported or permitted by apple on their platforms, see [this](contrib/macos/README.txt) for more information. If you find this disagreeable consider using a platform that permits compiling from source.
|
||||
If you find this disagreeable consider using a platform that permits compiling from source.
|
||||
|
||||
### Windows <span id="windows-install" />
|
||||
|
||||
|
|
Loading…
Reference in New Issue