From 0708a0d8976cbbd163d2e2990136decea0b5112e Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 14 May 2021 13:07:44 -0400 Subject: [PATCH 01/45] initial network extension code for macos probably does not work --- CMakeLists.txt | 69 +++---- cmake/installer.cmake | 1 + cmake/macos_installer_deps.cmake | 91 ++-------- contrib/format.sh | 18 +- contrib/lokinet.svg | 22 +++ contrib/mac.sh | 28 +++ contrib/macos/Info.plist | 24 +++ contrib/macos/LokinetExtension.Info.plist | 31 ++++ contrib/macos/lokinet.entitlements.plist | 10 + contrib/macos/{uninstaller => }/mk-icns.sh | 0 contrib/macos/sign.sh.in | 8 + contrib/windows.sh | 5 + daemon/CMakeLists.txt | 68 ++++++- daemon/Lokinet.modulemap.in | 4 + daemon/lokinet.mm | 9 + daemon/lokinet.swift | 77 ++++++++ daemon/swift/Lokinet/module.modulemap | 4 + daemon/swift/LokinetMain.swift | 43 +++++ external/CMakeLists.txt | 18 +- include/llarp.hpp | 1 - include/lokinet-extension.hpp | 18 ++ llarp/CMakeLists.txt | 27 +++ llarp/config/config.cpp | 14 ++ llarp/config/config.hpp | 5 + llarp/framework.mm | 202 +++++++++++++++++++++ llarp/vpn/apple.hpp | 173 ------------------ llarp/vpn/platform.cpp | 10 +- readme.md | 9 +- 28 files changed, 678 insertions(+), 311 deletions(-) create mode 100644 contrib/lokinet.svg create mode 100755 contrib/mac.sh create mode 100644 contrib/macos/Info.plist create mode 100644 contrib/macos/LokinetExtension.Info.plist create mode 100644 contrib/macos/lokinet.entitlements.plist rename contrib/macos/{uninstaller => }/mk-icns.sh (100%) create mode 100755 contrib/macos/sign.sh.in create mode 100644 daemon/Lokinet.modulemap.in create mode 100644 daemon/lokinet.mm create mode 100644 daemon/lokinet.swift create mode 100644 daemon/swift/Lokinet/module.modulemap create mode 100644 daemon/swift/LokinetMain.swift create mode 100644 include/lokinet-extension.hpp create mode 100644 llarp/framework.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f982142c..9f9b1a4a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,14 @@ 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(LANGS ASM C CXX) +if(APPLE) + set(LANGS ${LANGS} OBJC Swift) +endif() + find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) - foreach(lang C CXX) + foreach(lang ${LANGS}) if(NOT DEFINED CMAKE_${lang}_COMPILER_LAUNCHER AND NOT CMAKE_${lang}_COMPILER MATCHES ".*/ccache") message(STATUS "Enabling ccache for ${lang}") set(CMAKE_${lang}_COMPILER_LAUNCHER ${CCACHE_PROGRAM} CACHE STRING "") @@ -15,10 +20,11 @@ if(CCACHE_PROGRAM) endforeach() endif() + project(lokinet VERSION 0.9.5 DESCRIPTION "lokinet - IP packet onion router" - LANGUAGES C CXX) + LANGUAGES ${LANGS}) set(RELEASE_MOTTO "A Series of Tubes" CACHE STRING "Release motto") @@ -32,7 +38,6 @@ endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") - # Core options option(USE_AVX2 "enable avx2 code" OFF) option(USE_NETNS "enable networking namespace support. Linux only" OFF) @@ -94,14 +99,6 @@ endif() add_definitions(-D${CMAKE_SYSTEM_NAME}) -if(MSVC_VERSION) - enable_language(ASM_MASM) - list(APPEND CMAKE_ASM_MASM_SOURCE_FILE_EXTENSIONS s) - add_definitions(-D_WIN32_WINNT=0x0600 -DNOMINMAX -DSODIUM_STATIC) -else() - enable_language(ASM) -endif() - include(cmake/solaris.cmake) include(cmake/win32.cmake) @@ -184,8 +181,12 @@ else() endif() -# this is messing with release builds -add_compile_options(-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0) +if(NOT APPLE) + add_compile_options(-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -Wall -Wextra -Wno-unknown-pragmas -Wno-unused-function -Wno-deprecated-declarations -Werror=vla) + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wno-unknown-warning-option) + endif() +endif() if (NOT CMAKE_SYSTEM_NAME MATCHES "Linux" AND SHADOW) message( FATAL_ERROR "shadow-framework is Linux only" ) @@ -213,17 +214,6 @@ if(TRACY_ROOT) endif() -if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - add_compile_options(-Wno-unknown-warning-option) -endif() - -if (NOT MSVC_VERSION) - add_compile_options(-Wall -Wextra -Wno-unknown-pragmas) - # vla are evil - add_compile_options(-Werror=vla) - add_compile_options(-Wno-unused-function -Wno-deprecated-declarations) -endif() - include(cmake/coverage.cmake) # these vars are set by the cmake toolchain spec @@ -231,18 +221,20 @@ if (WOW64_CROSS_COMPILE OR WIN64_CROSS_COMPILE) include(cmake/cross_compile.cmake) endif() -if(NATIVE_BUILD) - if(CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le) - add_compile_options(-mcpu=native -mtune=native) - else() - add_compile_options(-march=native -mtune=native) - endif() -elseif(NOT NON_PC_TARGET) - if (USE_AVX2) - add_compile_options(-march=haswell -mtune=haswell -mfpmath=sse) - else() - # Public binary releases - add_compile_options(-march=nocona -mtune=haswell -mfpmath=sse) +if(NOT APPLE) + if(NATIVE_BUILD) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL ppc64le) + add_compile_options(-mcpu=native -mtune=native) + else() + add_compile_options(-march=native -mtune=native) + endif() + elseif(NOT NON_PC_TARGET) + if (USE_AVX2) + add_compile_options(-march=haswell -mtune=haswell -mfpmath=sse) + else() + # Public binary releases + add_compile_options(-march=nocona -mtune=haswell -mfpmath=sse) + endif() endif() endif() @@ -332,12 +324,11 @@ endif() add_subdirectory(crypto) add_subdirectory(llarp) add_subdirectory(daemon) + + if(WITH_HIVE) add_subdirectory(pybind) endif() - - - if (NOT SHADOW) if(WITH_TESTS OR WITH_HIVE) add_subdirectory(test) diff --git a/cmake/installer.cmake b/cmake/installer.cmake index 789a88ee4..b08a9d7b4 100644 --- a/cmake/installer.cmake +++ b/cmake/installer.cmake @@ -14,3 +14,4 @@ endif() # This must always be last! include(CPack) + diff --git a/cmake/macos_installer_deps.cmake b/cmake/macos_installer_deps.cmake index a56995a73..b315b389b 100644 --- a/cmake/macos_installer_deps.cmake +++ b/cmake/macos_installer_deps.cmake @@ -1,8 +1,9 @@ # macos specific cpack stuff goes here +return() + # Here we build lokinet-network-control-panel into 'lokinet-gui.app' in "extra/" where a postinstall # script will then move it to /Applications/. - set(LOKINET_GUI_REPO "https://github.com/oxen-io/loki-network-control-panel.git" CACHE STRING "Can be set to override the default lokinet-gui git repository") set(LOKINET_GUI_CHECKOUT "origin/master" @@ -18,83 +19,25 @@ set(MACOS_NOTARIZE_PASS "" set(MACOS_NOTARIZE_ASC "" CACHE STRING "set macos notarization asc provider; can also set it in ~/.notarization.cmake") -include(ExternalProject) - -message(STATUS "Building UninstallLokinet.app") - -ExternalProject_Add(lokinet-uninstaller - SOURCE_DIR ${CMAKE_SOURCE_DIR}/contrib/macos/uninstaller - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR} -DMACOS_SIGN=${MACOS_SIGN_APP} - -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -) - -message(STATUS "Building LokinetGUI.app from ${LOKINET_GUI_REPO} @ ${LOKINET_GUI_CHECKOUT}") - if(NOT BUILD_STATIC_DEPS) message(FATAL_ERROR "Building an installer on macos requires -DBUILD_STATIC_DEPS=ON") endif() - - -ExternalProject_Add(lokinet-gui - DEPENDS oxenmq::oxenmq - GIT_REPOSITORY "${LOKINET_GUI_REPO}" - GIT_TAG "${LOKINET_GUI_CHECKOUT}" - CMAKE_ARGS -DMACOS_APP=ON -DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR} -DMACOS_SIGN=${MACOS_SIGN_APP} - -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -DBUILD_SHARED_LIBS=OFF - "-DOXENMQ_LIBRARIES=$$$$$" - "-DOXENMQ_INCLUDE_DIRS=$" - ) - -install(PROGRAMS ${CMAKE_SOURCE_DIR}/contrib/macos/lokinet_uninstall.sh - DESTINATION "bin/" - COMPONENT lokinet) - -install(DIRECTORY ${PROJECT_BINARY_DIR}/LokinetGUI.app - DESTINATION "../../Applications/Lokinet" - USE_SOURCE_PERMISSIONS - COMPONENT gui - PATTERN "*" - ) - -install(DIRECTORY ${PROJECT_BINARY_DIR}/UninstallLokinet.app - DESTINATION "../../Applications/Lokinet" - USE_SOURCE_PERMISSIONS - COMPONENT gui - PATTERN "*" - ) - -# copy files that will be later moved by the postinstall script to proper locations -install(FILES ${CMAKE_SOURCE_DIR}/contrib/macos/lokinet_macos_daemon_script.sh - ${CMAKE_SOURCE_DIR}/contrib/macos/network.loki.lokinet.daemon.plist - ${CMAKE_SOURCE_DIR}/contrib/macos/lokinet-newsyslog.conf - DESTINATION "extra/" - COMPONENT lokinet) - -set(CPACK_COMPONENTS_ALL lokinet gui) - -set(CPACK_COMPONENT_LOKINET_DISPLAY_NAME "Lokinet Service") -set(CPACK_COMPONENT_LOKINET_DESCRIPTION "Main Lokinet runtime service, managed by Launchd") - -set(CPACK_COMPONENT_GUI_DISPLAY_NAME "Lokinet GUI") -set(CPACK_COMPONENT_GUI_DESCRIPTION "Small GUI which provides stats and limited runtime control of the Lokinet service. Resides in the system tray.") - -set(CPACK_GENERATOR "productbuild") -set(CPACK_PACKAGING_INSTALL_PREFIX "/opt/lokinet") -set(CPACK_PREINSTALL_LOKINET_SCRIPT ${CMAKE_SOURCE_DIR}/contrib/macos/preinstall) -set(CPACK_POSTFLIGHT_LOKINET_SCRIPT ${CMAKE_SOURCE_DIR}/contrib/macos/postinstall) - -set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE.txt") - -set(CPACK_PRODUCTBUILD_IDENTITY_NAME "${MACOS_SIGN_PKG}") - -if(MACOS_SIGN_APP) - add_custom_target(sign ALL - echo "Signing lokinet and lokinet-vpn binaries" - COMMAND codesign -s "${MACOS_SIGN_APP}" --strict --options runtime --force -vvv $ $ - DEPENDS lokinet lokinet-vpn - ) -endif() +#set(CPACK_GENERATOR "Bundle") + +#set(MACOSX_BUNDLE_BUNDLE_NAME Lokinet) +#set(CPACK_BUNDLE_NAME Lokinet) +#set(CPACK_BUNDLE_PLIST ${CMAKE_SOURCE_DIR}/contrib/macos/Info.plist) +#set(CPACK_BUNDLE_ICON "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns") +#set(CPACK_BUNDLE_STARTUP_COMMAND ${CMAKE_BINARY_DIR}/daemon/lokinet) +#set(MACOSX_BUNDLE_GUI_IDENTIFIER org.lokinet.lokinet) +#set(MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router") +#set(MACOSX_BUNDLE_LONG_VERSION_STRING ${PROJECT_VERSION}) +#set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}) +#set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}) +#set(MACOSX_BUNDLE_COPYRIGHT "© 2021, The Loki Project") +#set(CPACK_BUNDLE_APPLE_ENTITLEMENTS ${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements) +#set(CPACK_BUNDLE_APPLE_CERT_APP "${MACOS_SIGN_APP}") if(MACOS_SIGN_APP AND MACOS_SIGN_PKG) if(NOT MACOS_NOTARIZE_USER) diff --git a/contrib/format.sh b/contrib/format.sh index f83c27436..26ed77d3c 100755 --- a/contrib/format.sh +++ b/contrib/format.sh @@ -18,7 +18,23 @@ fi cd "$(dirname $0)/../" if [ "$1" = "verify" ] ; then - exit $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.[hc](pp)?$' | grep -v '\#') | grep '' | wc -l) + if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.[hc](pp)?$' | grep -v '\#') | grep '' | wc -l) -ne 0 ] ; then + exit 1 + fi else $binary -i $(find jni daemon llarp include pybind | grep -E '\.[hc](pp)?$' | grep -v '\#') &> /dev/null fi + +swift_format=$(which swiftformat 2>/dev/null) +if [ $? -eq 0 ]; then + if [ "$1" = "verify" ] ; then + for f in $(find daemon | grep -E '\.swift$' | grep -v '\#') ; do + if [ $($swift_format --quiet --dryrun < "$f" | diff "$f" - | wc -l) -ne 0 ] ; then + exit 1 + fi + done + else + $swift_format --quiet $(find daemon | grep -E '\.swift$' | grep -v '\#') + fi + +fi diff --git a/contrib/lokinet.svg b/contrib/lokinet.svg new file mode 100644 index 000000000..f8e760248 --- /dev/null +++ b/contrib/lokinet.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + diff --git a/contrib/mac.sh b/contrib/mac.sh new file mode 100755 index 000000000..62e14802e --- /dev/null +++ b/contrib/mac.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# +# build the shit on mac +# t. jeff +# + +set -e +set +x +mkdir -p build-mac +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 \ + -DNATIVE_BUILD=OFF \ + -DSTATIC_LINK=ON \ + -DWITH_SYSTEMD=OFF \ + -DFORCE_OXENMQ_SUBMODULE=ON \ + -DSUBMODULE_CHECK=OFF \ + -DWITH_LTO=OFF \ + -DCMAKE_INSTALL_PREFIX=$(pwd) \ + -DCMAKE_BUILD_TYPE=Release \ + $@ .. +ninja install && ninja sign diff --git a/contrib/macos/Info.plist b/contrib/macos/Info.plist new file mode 100644 index 000000000..de014151e --- /dev/null +++ b/contrib/macos/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Lokinet + CFBundleExecutable + MacOS/lokinet + CFBundleIdentifier + org.lokinet.Daemon + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + lokinet + CFBundlePackageType + XPC! + CFBundleShortVersionString + 0.1 + CFBundleVersion + 0.1 + + diff --git a/contrib/macos/LokinetExtension.Info.plist b/contrib/macos/LokinetExtension.Info.plist new file mode 100644 index 000000000..bc6b357af --- /dev/null +++ b/contrib/macos/LokinetExtension.Info.plist @@ -0,0 +1,31 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Lokinet + CFBundleExecutable + lokinet-extension + CFBundleIdentifier + org.lokinet.NetworkExtension + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Lokinet + CFBundlePackageType + XPC! + CFBundleShortVersionString + 0.1 + CFBundleVersion + 0.1 + NSExtension + + NSExtensionPointIdentifier + com.apple.networkextension.packet-tunnel + NSExtensionPrincipalClass + Lokinet.LLARPPacketTunnel + + + diff --git a/contrib/macos/lokinet.entitlements.plist b/contrib/macos/lokinet.entitlements.plist new file mode 100644 index 000000000..589ce8b28 --- /dev/null +++ b/contrib/macos/lokinet.entitlements.plist @@ -0,0 +1,10 @@ + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider + + + diff --git a/contrib/macos/uninstaller/mk-icns.sh b/contrib/macos/mk-icns.sh similarity index 100% rename from contrib/macos/uninstaller/mk-icns.sh rename to contrib/macos/mk-icns.sh diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in new file mode 100755 index 000000000..fc1136d9b --- /dev/null +++ b/contrib/macos/sign.sh.in @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -x +set -e +for file in "${SIGN_TARGET}/Contents/Frameworks/lokinet-extension.framework" "${SIGN_TARGET}/Contents/MacOS/Lokinet" "${SIGN_TARGET}" ; do + codesign -vvvv --force -s "${CODESIGN_KEY}" --entitlements "${SIGN_ENTITLEMENTS}" --deep --timestamp --options=runtime "$file" +done + +codesign --verify "${SIGN_TARGET}" diff --git a/contrib/windows.sh b/contrib/windows.sh index c1224afe1..5d6bf399c 100755 --- a/contrib/windows.sh +++ b/contrib/windows.sh @@ -1,4 +1,9 @@ #!/bin/bash +# +# helper script for me for when i cross compile for windows +# t. jeff +# + set -e set +x mkdir -p build-windows diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 7c6e8a45b..257daebed 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,4 +1,16 @@ -add_executable(lokinet lokinet.cpp) +if(APPLE) + option(WITH_SWIFT "use swift" ON) + if(WITH_SWIFT) + add_executable(lokinet lokinet.swift) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) + target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) + else() + add_executable(lokinet lokinet.mm) + endif() + target_link_libraries(lokinet PUBLIC lokinet-extension) +else() + add_executable(lokinet lokinet.cpp) +endif() add_executable(lokinet-vpn lokinet-vpn.cpp) add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) enable_lto(lokinet lokinet-vpn lokinet-bootstrap) @@ -30,7 +42,12 @@ if(NOT WIN32) target_link_libraries(lokinet-bootstrap PUBLIC OpenSSL::SSL OpenSSL::Crypto) endif() -foreach(exe lokinet lokinet-vpn lokinet-bootstrap) +set(exetargets lokinet-vpn lokinet-bootstrap) +if(NOT APPLE) + set(exetargets lokinet ${exes}) +endif() + +foreach(exe ${exetargets}) if(WIN32 AND NOT MSVC_VERSION) target_sources(${exe} PRIVATE ../llarp/win32/version.rc) target_link_libraries(${exe} PRIVATE -static-libstdc++ -static-libgcc --static -Wl,--pic-executable,-e,mainCRTStartup,--subsystem,console:5.00) @@ -46,10 +63,55 @@ foreach(exe lokinet lokinet-vpn lokinet-bootstrap) target_compile_definitions(${exe} PRIVATE -DVERSIONTAG=${GIT_VERSION_REAL}) add_log_tag(${exe}) if(should_install) - install(TARGETS ${exe} RUNTIME DESTINATION bin COMPONENT lokinet) + if(APPLE) + install(TARGETS ${exe} BUNDLE DESTINATION "${CMAKE_BINARY_DIR}" COMPONENT lokinet) + else() + install(TARGETS ${exe} RUNTIME DESTINATION bin COMPONENT lokinet) + endif() endif() endforeach() +if(APPLE) +# add_custom_command(TARGET lokinet +# POST_BUILD +# COMMAND ${CMAKE_COMMAND} -E echo "setting rpath" +# COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $ +# ) + add_custom_target(icons ALL + COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns + DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh) + add_dependencies(lokinet icons lokinet-extension) + install(TARGETS lokinet-extension FRAMEWORK DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app/Contents/Frameworks" COMPONENT lokinet) + 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_MAJOR}.${lokinet_VERSION_MINOR}.${lokinet_VERSION_PATCH}" + MACOSX_BUNDLE_LONG_VERSION_STRING "${lokinet_VERSION}.$lokinet_VERSION_MINOR}" + MACOSX_BUNDLE_SHORT_VERSION_STRING "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}" + MACOSX_BUNDLE_GUI_IDENTIFIER "org.lokinet.lokinet" + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/contrib/macos/Info.plist" + MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" + MACOSX_BUNDLE_COPYRIGHT "© 2021, The Loki Project") + option(CODESIGN_KEY "codesign all the shit with this key" OFF) + if (CODESIGN_KEY) + message(STATUS "codesigning with ${CODESIGN_KEY}") + set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app") + set(SIGN_ENTITLEMENTS "${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements.plist") + configure_file( + "${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in" + "${CMAKE_BINARY_DIR}/sign.sh") + add_custom_target( + sign + DEPENDS "${CMAKE_BINARY_DIR}/sign.sh" lokinet lokinet-extension + COMMAND "${CMAKE_BINARY_DIR}/sign.sh" + ) + else() + message(STATUS "will not codesign") + endif() +endif() + if(SETCAP) install(CODE "execute_process(COMMAND ${SETCAP} cap_net_admin,cap_net_bind_service=+eip ${CMAKE_INSTALL_PREFIX}/bin/lokinet)") endif() diff --git a/daemon/Lokinet.modulemap.in b/daemon/Lokinet.modulemap.in new file mode 100644 index 000000000..607823e38 --- /dev/null +++ b/daemon/Lokinet.modulemap.in @@ -0,0 +1,4 @@ + +module LokinetExtension { + header "@CMAKE_SOURCE_DIR@/include/lokinet-extension.hpp" +} \ No newline at end of file diff --git a/daemon/lokinet.mm b/daemon/lokinet.mm new file mode 100644 index 000000000..1baa58379 --- /dev/null +++ b/daemon/lokinet.mm @@ -0,0 +1,9 @@ +#import +#include + + +int main (int argc, const char * argv[]) +{ + + return 0; +} diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift new file mode 100644 index 000000000..28eefe06c --- /dev/null +++ b/daemon/lokinet.swift @@ -0,0 +1,77 @@ +// AppDelegateExtension.swift + +import Foundation +import LokinetExtension +import NetworkExtension + +class LokinetMain: NSObject { + var vpnManager = NETunnelProviderManager() + + let lokinetComponent = "org.lokinet.NetworkExtension" + var lokinetAdminTimer: DispatchSourceTimer? + + func runMain() { + print("Starting up lokinet") + NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in + if let error = error { + print(error) + } + + if let savedManagers = savedManagers { + for manager in savedManagers { + if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent { + print("Found saved VPN Manager") + self.vpnManager = manager + } + } + } + let providerProtocol = NETunnelProviderProtocol() + providerProtocol.serverAddress = "lokinet" + providerProtocol.providerBundleIdentifier = self.lokinetComponent + self.vpnManager.protocolConfiguration = providerProtocol + self.vpnManager.isEnabled = true + self.vpnManager.saveToPreferences(completionHandler: { error -> Void in + if error != nil { + print("Error saving to preferences") + } else { + print("saved...") + self.vpnManager.loadFromPreferences(completionHandler: { error in + if error != nil { + print("Error loading from preferences") + } else { + do { + print("Trying to start") + self.initializeConnectionObserver() + try self.vpnManager.connection.startVPNTunnel() + } catch let error as NSError { + print(error) + } catch { + print("There was a fatal error") + } + } + }) + } + }) + } + } + + func initializeConnectionObserver() { + NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: vpnManager.connection, queue: OperationQueue.main) { _ -> Void in + + if self.vpnManager.connection.status == .invalid { + print("VPN configuration is invalid") + } else if self.vpnManager.connection.status == .disconnected { + print("VPN is disconnected.") + } else if self.vpnManager.connection.status == .connecting { + print("VPN is connecting...") + } else if self.vpnManager.connection.status == .reasserting { + print("VPN is reasserting...") + } else if self.vpnManager.connection.status == .disconnecting { + print("VPN is disconnecting...") + } + } + } +} + +let lokinet = LokinetMain() +lokinet.runMain() diff --git a/daemon/swift/Lokinet/module.modulemap b/daemon/swift/Lokinet/module.modulemap new file mode 100644 index 000000000..fda10e4b7 --- /dev/null +++ b/daemon/swift/Lokinet/module.modulemap @@ -0,0 +1,4 @@ + +module Lokinet { + header "lokinet-extension.hpp" +} \ No newline at end of file diff --git a/daemon/swift/LokinetMain.swift b/daemon/swift/LokinetMain.swift new file mode 100644 index 000000000..561df3e7f --- /dev/null +++ b/daemon/swift/LokinetMain.swift @@ -0,0 +1,43 @@ +// AppDelegateExtension.swift +// lifed from yggdrasil network ios port +// + +import Foundation +import Lokinet +import NetworkExtension + +class LokinetMain: PlatformAppDelegate { + var vpnManager = NETunnelProviderManager() + var app = NSApplication.shared() + let lokinetComponent = "org.lokinet.NetworkExtension" + var lokinetAdminTimer: DispatchSourceTimer? + + func runMain() { + print("Starting up lokinet") + NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in + if let error = error { + print(error) + } + + if let savedManagers = savedManagers { + for manager in savedManagers { + if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent { + print("Found saved VPN Manager") + self.vpnManager = manager + } + } + } + + self.vpnManager.loadFromPreferences(completionHandler: { (error: Error?) in + if let error = error { + print(error) + } + self.vpnManager.localizedDescription = "Lokinet" + self.vpnManager.isEnabled = true + }) + } + app.finishLaunching() + app.run() + print("end") + } +} diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 9634f0036..f574f4193 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -50,6 +50,16 @@ add_library(uvw INTERFACE) target_include_directories(uvw INTERFACE uvw/src) target_link_libraries(uvw INTERFACE libuv) + + +# We don't need any of these as we don't use the ssl crypto helper code at all: +set(ENABLE_GNUTLS OFF CACHE BOOL "Disable gnutls for ngtcp2") +set(ENABLE_OPENSSL OFF CACHE BOOL "Disable openssl for ngtcp2") +set(ENABLE_BORINGSSL OFF CACHE BOOL "Disable boringssl for ngtcp2") + +add_definitions(-D_GNU_SOURCE) +add_subdirectory(ngtcp2 EXCLUDE_FROM_ALL) + # cpr configuration. Ideally we'd just do this via add_subdirectory, but cpr's cmake requires # 3.15+, and we target lower than that (and this is fairly simple to build). @@ -75,11 +85,3 @@ target_link_libraries(cpr PUBLIC CURL::libcurl) target_include_directories(cpr PUBLIC cpr/include) target_compile_definitions(cpr PUBLIC CPR_CURL_NOSIGNAL) add_library(cpr::cpr ALIAS cpr) - -# We don't need any of these as we don't use the ssl crypto helper code at all: -set(ENABLE_GNUTLS OFF CACHE BOOL "Disable gnutls for ngtcp2") -set(ENABLE_OPENSSL OFF CACHE BOOL "Disable openssl for ngtcp2") -set(ENABLE_BORINGSSL OFF CACHE BOOL "Disable boringssl for ngtcp2") - -add_definitions(-D_GNU_SOURCE) -add_subdirectory(ngtcp2 EXCLUDE_FROM_ALL) diff --git a/include/llarp.hpp b/include/llarp.hpp index e333e2495..5838d3569 100644 --- a/include/llarp.hpp +++ b/include/llarp.hpp @@ -120,7 +120,6 @@ namespace llarp std::unique_ptr> closeWaiter; }; - } // namespace llarp #endif diff --git a/include/lokinet-extension.hpp b/include/lokinet-extension.hpp new file mode 100644 index 000000000..5bbae9946 --- /dev/null +++ b/include/lokinet-extension.hpp @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +struct ContextWrapper; + +@interface LLARPPacketTunnel : NEPacketTunnelProvider +{ + @private + struct ContextWrapper* m_Context; +} +- (void)startTunnelWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError* error))completionHandler; + +- (void)stopTunnelWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler; + +@end diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 3ae31ae4e..aaf388457 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -262,6 +262,33 @@ if(BUILD_LIBLOKINET) add_log_tag(lokinet-shared) endif() +if(APPLE) + find_library(NETEXT NetworkExtension REQUIRED) + find_library(COREFOUNDATION CoreFoundation REQUIRED) + + add_library(lokinet-extension SHARED + framework.mm + ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) + target_include_directories(lokinet-extension PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}) + target_link_libraries(lokinet-extension PUBLIC + liblokinet + ${COREFOUNDATION} + ${NETEXT}) + + set_target_properties(lokinet-extension PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION CXX + MACOSX_FRAMEWORK_IDENTIFIER org.lokinet.NetworkExtension + MACOSX_FRAMEWORK_INFO_PLIST ${CMAKE_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist + # "current version" in semantic format in Mach-O binary file + VERSION 16.4.0 + # "compatibility version" in semantic format in Mach-O binary file + SOVERSION 1.0.0 + PUBLIC_HEADER ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) + +endif() + foreach(lokinet_lib liblokinet lokinet-platform lokinet-util lokinet-cryptography) add_log_tag(${lokinet_lib}) endforeach() diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 4e1b4c80e..3542e9326 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -1446,4 +1446,18 @@ namespace llarp return config; } +#ifdef __APPLE__ + std::shared_ptr + Config::NetworkExtensionConfig() + { + auto config = std::make_shared(fs::path{}); + config->Load(); + config->logging.m_logLevel = eLogInfo; + config->api.m_enableRPCServer = false; + config->network.m_saveProfiles = false; + config->bootstrap.files.clear(); + return config; + } +#endif + } // namespace llarp diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 03f7a000c..35360aeb8 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -260,6 +260,11 @@ namespace llarp static std::shared_ptr EmbeddedConfig(); +#ifdef __APPLE__ + static std::shared_ptr + NetworkExtensionConfig(); +#endif + private: /// Load (initialize) a default config. /// diff --git a/llarp/framework.mm b/llarp/framework.mm new file mode 100644 index 000000000..a5bd7d93f --- /dev/null +++ b/llarp/framework.mm @@ -0,0 +1,202 @@ +#include +#include + +#include +#include +#include + +#include + +namespace llarp::apple +{ + struct FrameworkContext : public llarp::Context + { + + explicit FrameworkContext(NEPacketTunnelProvider * tunnel); + + ~FrameworkContext() {} + + std::shared_ptr + makeVPNPlatform() override; + + void + Start(); + + private: + NEPacketTunnelProvider * m_Tunnel; + std::unique_ptr m_Runner; + }; + + class VPNInterface final : public vpn::NetworkInterface + { + NEPacketTunnelProvider * m_Tunnel; + + static inline constexpr auto PacketQueueSize = 1024; + + thread::Queue m_ReadQueue; + + void + OfferReadPacket(NSData * data) + { + llarp::net::IPPacket pkt; + const llarp_buffer_t buf{static_cast(data.bytes), data.length}; + if(pkt.Load(buf)) + m_ReadQueue.tryPushBack(std::move(pkt)); + } + + public: + explicit VPNInterface(NEPacketTunnelProvider * tunnel) + : m_Tunnel{tunnel}, + m_ReadQueue{PacketQueueSize} + { + auto handler = + [this](NSArray * packets, NSArray *) + { + NSUInteger num = [packets count]; + for(NSUInteger idx = 0; idx < num ; ++idx) + { + NSData * pkt = [packets objectAtIndex:idx]; + OfferReadPacket(pkt); + } + }; + [m_Tunnel.packetFlow readPacketsWithCompletionHandler:handler]; + } + + int + PollFD() const override + { + return -1; + } + + std::string + IfName() const override + { + return ""; + } + + net::IPPacket + ReadNextPacket() override + { + net::IPPacket pkt{}; + if(not m_ReadQueue.empty()) + pkt = m_ReadQueue.popFront(); + return pkt; + } + + bool + WritePacket(net::IPPacket pkt) override + { + const sa_family_t fam = pkt.IsV6() ? AF_INET6 : AF_INET; + const uint8_t * pktbuf = pkt.buf; + const size_t pktsz = pkt.sz; + NSData * datapkt = [NSData dataWithBytes:pktbuf length:pktsz]; + NEPacket * npkt = [[NEPacket alloc] initWithData:datapkt protocolFamily:fam]; + NSArray * pkts = @[npkt]; + return [m_Tunnel.packetFlow writePacketObjects:pkts]; + } + + }; + + class VPNPlatform final : public vpn::Platform + { + NEPacketTunnelProvider * m_Tunnel; + public: + explicit VPNPlatform(NEPacketTunnelProvider * tunnel) + : m_Tunnel{tunnel} + { + } + + std::shared_ptr + ObtainInterface(vpn::InterfaceInfo) override + { + return std::make_shared(m_Tunnel); + } + }; + + + FrameworkContext::FrameworkContext(NEPacketTunnelProvider * tunnel) : + llarp::Context{}, + m_Tunnel{tunnel} + { + } + + void + FrameworkContext::Start() + { + std::promise result; + + m_Runner = std::make_unique( + [&result, this]() + { + const RuntimeOptions opts{}; + try + { + Setup(opts); + Configure(llarp::Config::NetworkExtensionConfig()); + } + catch(std::exception & ) + { + result.set_exception(std::current_exception()); + return; + } + result.set_value(); + Run(opts); + }); + + auto ftr = result.get_future(); + ftr.get(); + } + + std::shared_ptr + FrameworkContext::makeVPNPlatform() + { + return std::make_shared(m_Tunnel); + } +} + + +struct ContextWrapper +{ + std::shared_ptr m_Context; +public: + explicit ContextWrapper(NEPacketTunnelProvider * tunnel) : + m_Context{std::make_shared(tunnel)} + {} + + void + Start() + { + m_Context->Start(); + } + + void + Stop() + { + m_Context->CloseAsync(); + m_Context->Wait(); + } +}; + + + +@implementation LLARPPacketTunnel + +- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(NSError *error))completionHandler { + m_Context = new ContextWrapper{self}; + m_Context->Start(); + completionHandler(nullptr); +} + +- (void)stopTunnelWithReason:(NEProviderStopReason)reason +completionHandler:(void (^)(void))completionHandler { + if(m_Context) + { + m_Context->Stop(); + delete m_Context; + m_Context = nullptr; + } + completionHandler(); +} + + +@end diff --git a/llarp/vpn/apple.hpp b/llarp/vpn/apple.hpp index f20c50ce3..e69de29bb 100644 --- a/llarp/vpn/apple.hpp +++ b/llarp/vpn/apple.hpp @@ -1,173 +0,0 @@ -#pragma once - -#include -#include "common.hpp" - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace llarp::vpn -{ - class AppleInterface : public NetworkInterface - { - const int m_FD; - const InterfaceInfo m_Info; - std::string m_IfName; - - static void - Exec(std::string cmd) - { - LogDebug(cmd); - system(cmd.c_str()); - } - - public: - AppleInterface(InterfaceInfo info) - : m_FD{::socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL)}, m_Info{std::move(info)} - { - if (m_FD == -1) - throw std::invalid_argument{"cannot open control socket: " + std::string{strerror(errno)}}; - - ctl_info cinfo{}; - const std::string apple_utun = "com.apple.net.utun_control"; - std::copy_n(apple_utun.c_str(), apple_utun.size(), cinfo.ctl_name); - if (::ioctl(m_FD, CTLIOCGINFO, &cinfo) < 0) - { - ::close(m_FD); - throw std::runtime_error{"ioctl CTLIOCGINFO call failed: " + std::string{strerror(errno)}}; - } - sockaddr_ctl addr{}; - addr.sc_id = cinfo.ctl_id; - - addr.sc_len = sizeof(addr); - addr.sc_family = AF_SYSTEM; - addr.ss_sysaddr = AF_SYS_CONTROL; - addr.sc_unit = 0; - - if (connect(m_FD, (sockaddr*)&addr, sizeof(addr)) < 0) - { - ::close(m_FD); - throw std::runtime_error{ - "cannot connect to control socket address: " + std::string{strerror(errno)}}; - } - uint32_t namesz = IFNAMSIZ; - char name[IFNAMSIZ + 1]{}; - if (getsockopt(m_FD, SYSPROTO_CONTROL, 2, name, &namesz) < 0) - { - ::close(m_FD); - throw std::runtime_error{ - "cannot query for interface name: " + std::string{strerror(errno)}}; - } - m_IfName = name; - for (const auto& ifaddr : m_Info.addrs) - { - if (ifaddr.fam == AF_INET) - { - const huint32_t addr = net::TruncateV6(ifaddr.range.addr); - const huint32_t netmask = net::TruncateV6(ifaddr.range.netmask_bits); - const huint32_t daddr = addr & netmask; - Exec( - "/sbin/ifconfig " + m_IfName + " " + addr.ToString() + " " + daddr.ToString() - + " mtu 1500 netmask 255.255.255.255 up"); - Exec( - "/sbin/route add " + daddr.ToString() + " -netmask " + netmask.ToString() - + " -interface " + m_IfName); - Exec("/sbin/route add " + addr.ToString() + " -interface lo0"); - } - else if (ifaddr.fam == AF_INET6) - { - Exec("/sbin/ifconfig " + m_IfName + " inet6 " + ifaddr.range.ToString()); - } - } - } - - ~AppleInterface() - { - ::close(m_FD); - } - - std::string - IfName() const override - { - return m_IfName; - } - - int - PollFD() const override - { - return m_FD; - } - - net::IPPacket - ReadNextPacket() override - { - constexpr int uintsize = sizeof(unsigned int); - net::IPPacket pkt{}; - unsigned int pktinfo = 0; - const struct iovec vecs[2] = { - {.iov_base = &pktinfo, .iov_len = uintsize}, - {.iov_base = pkt.buf, .iov_len = sizeof(pkt.buf)}}; - int sz = readv(m_FD, vecs, 2); - if (sz >= uintsize) - pkt.sz = sz - uintsize; - else if (sz >= 0 || errno == EAGAIN || errno == EWOULDBLOCK) - pkt.sz = 0; - else - throw std::error_code{errno, std::system_category()}; - return pkt; - } - - bool - WritePacket(net::IPPacket pkt) override - { - static unsigned int af4 = htonl(AF_INET); - static unsigned int af6 = htonl(AF_INET6); - - const struct iovec vecs[2] = { - {.iov_base = pkt.IsV6() ? &af6 : &af4, .iov_len = sizeof(unsigned int)}, - {.iov_base = pkt.buf, .iov_len = pkt.sz}}; - - ssize_t n = writev(m_FD, vecs, 2); - if (n >= (int)sizeof(unsigned int)) - { - n -= sizeof(unsigned int); - return static_cast(n) == pkt.sz; - } - return false; - } - }; - - class ApplePlatform : public Platform - { - public: - std::shared_ptr - ObtainInterface(InterfaceInfo info) override - { - return std::make_shared(std::move(info)); - } - }; -} // namespace llarp::vpn diff --git a/llarp/vpn/platform.cpp b/llarp/vpn/platform.cpp index 0784ba110..341e28fcb 100644 --- a/llarp/vpn/platform.cpp +++ b/llarp/vpn/platform.cpp @@ -1,3 +1,6 @@ + +#include + #ifdef _WIN32 #include "win32.hpp" #endif @@ -8,9 +11,8 @@ #include "linux.hpp" #endif #endif -#ifdef __APPLE__ -#include "apple.hpp" -#endif + +#include namespace llarp::vpn { @@ -30,7 +32,7 @@ namespace llarp::vpn #endif #endif #ifdef __APPLE__ - plat = std::make_shared(); + throw std::runtime_error{"not supported"}; #endif return plat; } diff --git a/readme.md b/readme.md index b0b08e446..9122baf13 100644 --- a/readme.md +++ b/readme.md @@ -62,14 +62,7 @@ alternatively you can build from source, make sure you have cmake, libuv and xco $ git clone --recursive https://github.com/oxen-io/lokinet $ cd lokinet - $ mkdir build - $ cd build - $ cmake .. -DBUILD_STATIC_DEPS=ON -DBUILD_SHARED_LIBS=OFF -DSTATIC_LINK=ON - $ make -j$(sysctl -n hw.ncpu) - -install: - - $ sudo make install + $ ./contrib/mac.sh -DCODESIGN_KEY='insert your key identity here' ### Windows From 5edd045c9b1cfb1c8b605b4c91805b2d5825e6bf Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 30 Jun 2021 07:21:17 -0400 Subject: [PATCH 02/45] add swift version bullshit file and additional bullshittery --- .swift-version | 1 + CMakeLists.txt | 1 + contrib/format.sh | 4 +- contrib/macos/Info.plist | 2 +- contrib/macos/LokinetExtension.Info.plist | 31 ---- contrib/macos/LokinetExtension.Info.plist.in | 40 +++++ .../lokinet-extension.entitlements.plist.in | 25 +++ contrib/macos/lokinet.entitlements.plist | 10 -- contrib/macos/lokinet.entitlements.plist.in | 24 +++ contrib/macos/sign.sh.in | 8 +- daemon/CMakeLists.txt | 58 ++++--- daemon/lokinet.cpp | 8 + daemon/lokinet.mm | 9 - daemon/lokinet.swift | 68 +++++--- daemon/swift/Lokinet/module.modulemap | 4 - daemon/swift/LokinetMain.swift | 43 ----- include/lokinet-extension.hpp | 5 +- llarp/CMakeLists.txt | 20 ++- llarp/framework.mm | 163 ++++++++++-------- llarp/util/logging/apple_logger.hpp | 32 ++++ llarp/util/logging/apple_logger.mm | 38 ++++ readme.md | 2 +- 22 files changed, 358 insertions(+), 238 deletions(-) create mode 100644 .swift-version delete mode 100644 contrib/macos/LokinetExtension.Info.plist create mode 100644 contrib/macos/LokinetExtension.Info.plist.in create mode 100644 contrib/macos/lokinet-extension.entitlements.plist.in delete mode 100644 contrib/macos/lokinet.entitlements.plist create mode 100644 contrib/macos/lokinet.entitlements.plist.in delete mode 100644 daemon/lokinet.mm delete mode 100644 daemon/swift/Lokinet/module.modulemap delete mode 100644 daemon/swift/LokinetMain.swift create mode 100644 llarp/util/logging/apple_logger.hpp create mode 100644 llarp/util/logging/apple_logger.mm diff --git a/.swift-version b/.swift-version new file mode 100644 index 000000000..8ae03c119 --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +5.4.2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f9b1a4a0..aa6fc1290 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ if(RELEASE_MOTTO AND CMAKE_BUILD_TYPE MATCHES "[Rr][Ee][Ll][Ee][Aa][Ss][Ee]") add_definitions(-DLLARP_RELEASE_MOTTO="${RELEASE_MOTTO}") endif() +set(LOKINET_VERSION "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}.${lokinet_VERSION_PATCH}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") diff --git a/contrib/format.sh b/contrib/format.sh index 26ed77d3c..5b5f5a495 100755 --- a/contrib/format.sh +++ b/contrib/format.sh @@ -18,11 +18,11 @@ fi cd "$(dirname $0)/../" if [ "$1" = "verify" ] ; then - if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.[hc](pp)?$' | grep -v '\#') | grep '' | wc -l) -ne 0 ] ; then + if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|mm)$' | grep -v '\#') | grep '' | wc -l) -ne 0 ] ; then exit 1 fi else - $binary -i $(find jni daemon llarp include pybind | grep -E '\.[hc](pp)?$' | grep -v '\#') &> /dev/null + $binary -i $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|mm)$' | grep -v '\#') &> /dev/null fi swift_format=$(which swiftformat 2>/dev/null) diff --git a/contrib/macos/Info.plist b/contrib/macos/Info.plist index de014151e..d39aed3a8 100644 --- a/contrib/macos/Info.plist +++ b/contrib/macos/Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable MacOS/lokinet CFBundleIdentifier - org.lokinet.Daemon + com.loki-project.lokinet CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/contrib/macos/LokinetExtension.Info.plist b/contrib/macos/LokinetExtension.Info.plist deleted file mode 100644 index bc6b357af..000000000 --- a/contrib/macos/LokinetExtension.Info.plist +++ /dev/null @@ -1,31 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - Lokinet - CFBundleExecutable - lokinet-extension - CFBundleIdentifier - org.lokinet.NetworkExtension - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - Lokinet - CFBundlePackageType - XPC! - CFBundleShortVersionString - 0.1 - CFBundleVersion - 0.1 - NSExtension - - NSExtensionPointIdentifier - com.apple.networkextension.packet-tunnel - NSExtensionPrincipalClass - Lokinet.LLARPPacketTunnel - - - diff --git a/contrib/macos/LokinetExtension.Info.plist.in b/contrib/macos/LokinetExtension.Info.plist.in new file mode 100644 index 000000000..7f6ecadbb --- /dev/null +++ b/contrib/macos/LokinetExtension.Info.plist.in @@ -0,0 +1,40 @@ + + + + + CFBundleDisplayName + Lokinet + + CFBundleExecutable + lokinet-extension + + CFBundleIdentifier + com.loki-project.lokinet.network-extension + + CFBundleInfoDictionaryVersion + 6.0 + + CFBundlePackageType + XPC! + + CFBundleName + lokinet + + CFBundleVersion + ${LOKINET_VERSION} + + ITSAppUsesNonExemptEncryption + + + LSMinimumSystemVersion + 11.0 + + NSExtension + + NSExtensionPointIdentifier + com.apple.networkextension.packet-tunnel + NSExtensionPrincipalClass + LLARPPacketTunnel + + + diff --git a/contrib/macos/lokinet-extension.entitlements.plist.in b/contrib/macos/lokinet-extension.entitlements.plist.in new file mode 100644 index 000000000..6f8dfb41b --- /dev/null +++ b/contrib/macos/lokinet-extension.entitlements.plist.in @@ -0,0 +1,25 @@ + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider + + + com.apple.security.network.client + + + diff --git a/contrib/macos/lokinet.entitlements.plist b/contrib/macos/lokinet.entitlements.plist deleted file mode 100644 index 589ce8b28..000000000 --- a/contrib/macos/lokinet.entitlements.plist +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.developer.networking.networkextension - - packet-tunnel-provider - - - diff --git a/contrib/macos/lokinet.entitlements.plist.in b/contrib/macos/lokinet.entitlements.plist.in new file mode 100644 index 000000000..66bbbb80c --- /dev/null +++ b/contrib/macos/lokinet.entitlements.plist.in @@ -0,0 +1,24 @@ + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider + + + com.apple.security.network.client + + + diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in index fc1136d9b..c255a94e8 100755 --- a/contrib/macos/sign.sh.in +++ b/contrib/macos/sign.sh.in @@ -1,8 +1,6 @@ #!/usr/bin/env bash -set -x set -e -for file in "${SIGN_TARGET}/Contents/Frameworks/lokinet-extension.framework" "${SIGN_TARGET}/Contents/MacOS/Lokinet" "${SIGN_TARGET}" ; do - codesign -vvvv --force -s "${CODESIGN_KEY}" --entitlements "${SIGN_ENTITLEMENTS}" --deep --timestamp --options=runtime "$file" +codesign --verbose=4 --force -s "${CODESIGN_KEY}" --entitlements "${NETEXT_ENTITLEMENTS}" --deep --timestamp --options=runtime "${SIGN_TARGET}/Contents/Frameworks/lokinet-extension.framework" +for file in "${SIGN_TARGET}/Contents/MacOS/Lokinet" "${SIGN_TARGET}" ; do + codesign --verbose=4 --force -s "${CODESIGN_KEY}" --entitlements "${LOKINET_ENTITLEMENTS}" --deep --timestamp --options=runtime "$file" done - -codesign --verify "${SIGN_TARGET}" diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 257daebed..a03ebef2a 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,19 +1,17 @@ if(APPLE) - option(WITH_SWIFT "use swift" ON) - if(WITH_SWIFT) - add_executable(lokinet lokinet.swift) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) - target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) - else() - add_executable(lokinet lokinet.mm) - endif() + set(LOKINET_SWIFT_SOURCES lokinet.swift) + add_executable(lokinet ${LOKINET_SWIFT_SOURCES}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) + target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) target_link_libraries(lokinet PUBLIC lokinet-extension) + add_executable(lokinet-old lokinet.cpp) + enable_lto(lokinet-old) else() add_executable(lokinet lokinet.cpp) + add_executable(lokinet-vpn lokinet-vpn.cpp) + add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) + enable_lto(lokinet lokinet-vpn lokinet-bootstrap) endif() -add_executable(lokinet-vpn lokinet-vpn.cpp) -add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) -enable_lto(lokinet lokinet-vpn lokinet-bootstrap) if(TRACY_ROOT) target_sources(lokinet PRIVATE ${TRACY_ROOT}/TracyClient.cpp) @@ -35,16 +33,19 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") endif() endif() -target_link_libraries(lokinet-bootstrap PUBLIC cpr::cpr) -if(NOT WIN32) - find_package(OpenSSL REQUIRED) - # because debian sid's curl doesn't link against openssl for some godawful cursed reason - target_link_libraries(lokinet-bootstrap PUBLIC OpenSSL::SSL OpenSSL::Crypto) +if(NOT APPLE) + target_link_libraries(lokinet-bootstrap PUBLIC cpr::cpr) + if(NOT WIN32) + find_package(OpenSSL REQUIRED) + # because debian sid's curl doesn't link against openssl for some godawful cursed reason + target_link_libraries(lokinet-bootstrap PUBLIC OpenSSL::SSL OpenSSL::Crypto) + endif() endif() -set(exetargets lokinet-vpn lokinet-bootstrap) -if(NOT APPLE) - set(exetargets lokinet ${exes}) +if(APPLE) + set(exetargets lokinet-old lokinet) +else() + set(exetargets lokinet lokinet-vpn lokinet-bootstrap) endif() foreach(exe ${exetargets}) @@ -55,11 +56,11 @@ foreach(exe ${exetargets}) elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") target_link_directories(${exe} PRIVATE /usr/local/lib) endif() - target_link_libraries(${exe} PRIVATE liblokinet) + target_link_libraries(${exe} PUBLIC liblokinet) if(WITH_JEMALLOC) target_link_libraries(${exe} PUBLIC jemalloc) endif() - target_include_directories(${exe} PRIVATE ${CMAKE_SOURCE_DIR}) + target_include_directories(${exe} PUBLIC "${PROJECT_SOURCE_DIR}") target_compile_definitions(${exe} PRIVATE -DVERSIONTAG=${GIT_VERSION_REAL}) add_log_tag(${exe}) if(should_install) @@ -87,18 +88,23 @@ if(APPLE) MACOSX_BUNDLE TRUE MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router" MACOSX_BUNDLE_BUNDLE_NAME "Lokinet" - MACOSX_BUNDLE_BUNDLE_VERSION "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}.${lokinet_VERSION_PATCH}" + MACOSX_BUNDLE_BUNDLE_VERSION "${LOKINET_VERSION}" MACOSX_BUNDLE_LONG_VERSION_STRING "${lokinet_VERSION}.$lokinet_VERSION_MINOR}" MACOSX_BUNDLE_SHORT_VERSION_STRING "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}" - MACOSX_BUNDLE_GUI_IDENTIFIER "org.lokinet.lokinet" + MACOSX_BUNDLE_GUI_IDENTIFIER "com.loki-project.lokinet" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/contrib/macos/Info.plist" MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" MACOSX_BUNDLE_COPYRIGHT "© 2021, The Loki Project") option(CODESIGN_KEY "codesign all the shit with this key" OFF) - if (CODESIGN_KEY) + if (CODESIGN_KEY AND CODESIGN_TEAM_ID) message(STATUS "codesigning with ${CODESIGN_KEY}") - set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app") - set(SIGN_ENTITLEMENTS "${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements.plist") + set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app") + configure_file("${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements.plist.in" + "${CMAKE_BINARY_DIR}/lokinet.entitlements.plist") + configure_file("${CMAKE_SOURCE_DIR}/contrib/macos/lokinet-extension.entitlements.plist.in" + "${CMAKE_BINARY_DIR}/lokinet-extension.entitlements.plist") + set(LOKINET_ENTITLEMENTS "${CMAKE_BINARY_DIR}/lokinet.entitlements.plist") + set(NETEXT_ENTITLEMENTS "${CMAKE_BINARY_DIR}/lokinet-extension.entitlements.plist") configure_file( "${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in" "${CMAKE_BINARY_DIR}/sign.sh") diff --git a/daemon/lokinet.cpp b/daemon/lokinet.cpp index 316d1b856..52664e897 100644 --- a/daemon/lokinet.cpp +++ b/daemon/lokinet.cpp @@ -11,6 +11,10 @@ #include #endif +#ifdef __APPLE__ +#include +#endif + #include #include @@ -396,6 +400,10 @@ lokinet_main(int argc, char* argv[]) { return result; } +#ifdef __APPLE__ + llarp::LogContext::Instance().logStream.reset(new llarp::NSLogStream{}); +#endif + llarp::RuntimeOptions opts; #ifdef _WIN32 diff --git a/daemon/lokinet.mm b/daemon/lokinet.mm deleted file mode 100644 index 1baa58379..000000000 --- a/daemon/lokinet.mm +++ /dev/null @@ -1,9 +0,0 @@ -#import -#include - - -int main (int argc, const char * argv[]) -{ - - return 0; -} diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift index 28eefe06c..b80c01227 100644 --- a/daemon/lokinet.swift +++ b/daemon/lokinet.swift @@ -1,52 +1,70 @@ -// AppDelegateExtension.swift - +import AppKit import Foundation import LokinetExtension import NetworkExtension -class LokinetMain: NSObject { - var vpnManager = NETunnelProviderManager() +let app = NSApplication.shared - let lokinetComponent = "org.lokinet.NetworkExtension" +class LokinetMain: NSObject, NSApplicationDelegate { + var vpnManager = NETunnelProviderManager() + let lokinetComponent = "com.loki-project.lokinet.network-extension" var lokinetAdminTimer: DispatchSourceTimer? - func runMain() { - print("Starting up lokinet") - NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in + func applicationDidFinishLaunching(_: Notification) { + setupVPNJizz() + } + + func bail() { + app.terminate(self) + } + + func setupVPNJizz() { + NSLog("Starting up lokinet") + NETunnelProviderManager.loadAllFromPreferences { [self] (savedManagers: [NETunnelProviderManager]?, error: Error?) in if let error = error { - print(error) + NSLog(error.localizedDescription) + bail() } if let savedManagers = savedManagers { for manager in savedManagers { if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent { - print("Found saved VPN Manager") + NSLog("%@", manager) + NSLog("Found saved VPN Manager") self.vpnManager = manager } } } let providerProtocol = NETunnelProviderProtocol() - providerProtocol.serverAddress = "lokinet" + providerProtocol.serverAddress = "" + providerProtocol.username = "anonymous" providerProtocol.providerBundleIdentifier = self.lokinetComponent + providerProtocol.includeAllNetworks = true self.vpnManager.protocolConfiguration = providerProtocol self.vpnManager.isEnabled = true + self.vpnManager.isOnDemandEnabled = true self.vpnManager.saveToPreferences(completionHandler: { error -> Void in if error != nil { - print("Error saving to preferences") + NSLog("Error saving to preferences") + NSLog(error!.localizedDescription) + bail() } else { - print("saved...") self.vpnManager.loadFromPreferences(completionHandler: { error in if error != nil { - print("Error loading from preferences") + NSLog("Error loading from preferences") + NSLog(error!.localizedDescription) + bail() } else { do { - print("Trying to start") + NSLog("Trying to start") self.initializeConnectionObserver() try self.vpnManager.connection.startVPNTunnel() } catch let error as NSError { - print(error) + NSLog(error.localizedDescription) + bail() } catch { - print("There was a fatal error") + NSLog("There was a fatal error") + bail() } } }) @@ -57,21 +75,21 @@ class LokinetMain: NSObject { func initializeConnectionObserver() { NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: vpnManager.connection, queue: OperationQueue.main) { _ -> Void in - if self.vpnManager.connection.status == .invalid { - print("VPN configuration is invalid") + NSLog("VPN configuration is invalid") } else if self.vpnManager.connection.status == .disconnected { - print("VPN is disconnected.") + NSLog("VPN is disconnected.") } else if self.vpnManager.connection.status == .connecting { - print("VPN is connecting...") + NSLog("VPN is connecting...") } else if self.vpnManager.connection.status == .reasserting { - print("VPN is reasserting...") + NSLog("VPN is reasserting...") } else if self.vpnManager.connection.status == .disconnecting { - print("VPN is disconnecting...") + NSLog("VPN is disconnecting...") } } } } -let lokinet = LokinetMain() -lokinet.runMain() +let delegate = LokinetMain() +app.delegate = delegate +app.run() diff --git a/daemon/swift/Lokinet/module.modulemap b/daemon/swift/Lokinet/module.modulemap deleted file mode 100644 index fda10e4b7..000000000 --- a/daemon/swift/Lokinet/module.modulemap +++ /dev/null @@ -1,4 +0,0 @@ - -module Lokinet { - header "lokinet-extension.hpp" -} \ No newline at end of file diff --git a/daemon/swift/LokinetMain.swift b/daemon/swift/LokinetMain.swift deleted file mode 100644 index 561df3e7f..000000000 --- a/daemon/swift/LokinetMain.swift +++ /dev/null @@ -1,43 +0,0 @@ -// AppDelegateExtension.swift -// lifed from yggdrasil network ios port -// - -import Foundation -import Lokinet -import NetworkExtension - -class LokinetMain: PlatformAppDelegate { - var vpnManager = NETunnelProviderManager() - var app = NSApplication.shared() - let lokinetComponent = "org.lokinet.NetworkExtension" - var lokinetAdminTimer: DispatchSourceTimer? - - func runMain() { - print("Starting up lokinet") - NETunnelProviderManager.loadAllFromPreferences { (savedManagers: [NETunnelProviderManager]?, error: Error?) in - if let error = error { - print(error) - } - - if let savedManagers = savedManagers { - for manager in savedManagers { - if (manager.protocolConfiguration as? NETunnelProviderProtocol)?.providerBundleIdentifier == self.lokinetComponent { - print("Found saved VPN Manager") - self.vpnManager = manager - } - } - } - - self.vpnManager.loadFromPreferences(completionHandler: { (error: Error?) in - if let error = error { - print(error) - } - self.vpnManager.localizedDescription = "Lokinet" - self.vpnManager.isEnabled = true - }) - } - app.finishLaunching() - app.run() - print("end") - } -} diff --git a/include/lokinet-extension.hpp b/include/lokinet-extension.hpp index 5bbae9946..df436ab4e 100644 --- a/include/lokinet-extension.hpp +++ b/include/lokinet-extension.hpp @@ -6,13 +6,16 @@ struct ContextWrapper; @interface LLARPPacketTunnel : NEPacketTunnelProvider { - @private struct ContextWrapper* m_Context; } + - (void)startTunnelWithOptions:(NSDictionary*)options completionHandler:(void (^)(NSError* error))completionHandler; - (void)stopTunnelWithReason:(NEProviderStopReason)reason completionHandler:(void (^)(void))completionHandler; +- (void)handleAppMessage:(NSData*)messageData + completionHandler:(void (^)(NSData* responseData))completionHandler; + @end diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index aaf388457..6730dd0a5 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(lokinet-util util/fs.cpp util/json.cpp util/logging/android_logger.cpp + util/logging/apple_logger.mm util/logging/buffer.cpp util/logging/file_logger.cpp util/logging/json_logger.cpp @@ -37,6 +38,11 @@ target_link_libraries(lokinet-util PUBLIC oxenmq::oxenmq ) +if(APPLE) + find_library(FOUNDATION Foundation REQUIRED) + target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) +endif() + if(ANDROID) target_link_libraries(lokinet-util PUBLIC log) endif() @@ -263,6 +269,7 @@ if(BUILD_LIBLOKINET) endif() if(APPLE) + # god made apple so that man may suffer find_library(NETEXT NetworkExtension REQUIRED) find_library(COREFOUNDATION CoreFoundation REQUIRED) @@ -276,15 +283,18 @@ if(APPLE) ${COREFOUNDATION} ${NETEXT}) + configure_file(${CMAKE_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in + ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist) + set_target_properties(lokinet-extension PROPERTIES FRAMEWORK TRUE - FRAMEWORK_VERSION CXX - MACOSX_FRAMEWORK_IDENTIFIER org.lokinet.NetworkExtension - MACOSX_FRAMEWORK_INFO_PLIST ${CMAKE_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist + FRAMEWORK_VERSION ${lokinet_VERSION} + MACOSX_FRAMEWORK_IDENTIFIER com.loki-project.lokinet.network-extension + MACOSX_FRAMEWORK_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist # "current version" in semantic format in Mach-O binary file - VERSION 16.4.0 + VERSION ${lokinet_VERSION} # "compatibility version" in semantic format in Mach-O binary file - SOVERSION 1.0.0 + SOVERSION ${lokinet_VERSION} PUBLIC_HEADER ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) endif() diff --git a/llarp/framework.mm b/llarp/framework.mm index a5bd7d93f..032c2424a 100644 --- a/llarp/framework.mm +++ b/llarp/framework.mm @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -11,54 +12,51 @@ namespace llarp::apple { struct FrameworkContext : public llarp::Context { - - explicit FrameworkContext(NEPacketTunnelProvider * tunnel); + explicit FrameworkContext(NEPacketTunnelProvider* tunnel); + + ~FrameworkContext() + {} - ~FrameworkContext() {} - std::shared_ptr makeVPNPlatform() override; void Start(); - - private: - NEPacketTunnelProvider * m_Tunnel; + + private: + NEPacketTunnelProvider* const m_Tunnel; std::unique_ptr m_Runner; - }; + }; class VPNInterface final : public vpn::NetworkInterface { - NEPacketTunnelProvider * m_Tunnel; + NEPacketTunnelProvider* const m_Tunnel; static inline constexpr auto PacketQueueSize = 1024; - + thread::Queue m_ReadQueue; void - OfferReadPacket(NSData * data) + OfferReadPacket(NSData* data) { llarp::net::IPPacket pkt; - const llarp_buffer_t buf{static_cast(data.bytes), data.length}; - if(pkt.Load(buf)) + const llarp_buffer_t buf{static_cast(data.bytes), data.length}; + if (pkt.Load(buf)) m_ReadQueue.tryPushBack(std::move(pkt)); } - public: - explicit VPNInterface(NEPacketTunnelProvider * tunnel) - : m_Tunnel{tunnel}, - m_ReadQueue{PacketQueueSize} + public: + explicit VPNInterface(NEPacketTunnelProvider* tunnel) + : m_Tunnel{tunnel}, m_ReadQueue{PacketQueueSize} { - auto handler = - [this](NSArray * packets, NSArray *) + auto handler = [this](NSArray* packets, NSArray*) { + NSUInteger num = [packets count]; + for (NSUInteger idx = 0; idx < num; ++idx) { - NSUInteger num = [packets count]; - for(NSUInteger idx = 0; idx < num ; ++idx) - { - NSData * pkt = [packets objectAtIndex:idx]; - OfferReadPacket(pkt); - } - }; + NSData* pkt = [packets objectAtIndex:idx]; + OfferReadPacket(pkt); + } + }; [m_Tunnel.packetFlow readPacketsWithCompletionHandler:handler]; } @@ -73,12 +71,12 @@ namespace llarp::apple { return ""; } - + net::IPPacket ReadNextPacket() override { net::IPPacket pkt{}; - if(not m_ReadQueue.empty()) + if (not m_ReadQueue.empty()) pkt = m_ReadQueue.popFront(); return pkt; } @@ -87,61 +85,53 @@ namespace llarp::apple WritePacket(net::IPPacket pkt) override { const sa_family_t fam = pkt.IsV6() ? AF_INET6 : AF_INET; - const uint8_t * pktbuf = pkt.buf; + const uint8_t* pktbuf = pkt.buf; const size_t pktsz = pkt.sz; - NSData * datapkt = [NSData dataWithBytes:pktbuf length:pktsz]; - NEPacket * npkt = [[NEPacket alloc] initWithData:datapkt protocolFamily:fam]; - NSArray * pkts = @[npkt]; + NSData* datapkt = [NSData dataWithBytes:pktbuf length:pktsz]; + NEPacket* npkt = [[NEPacket alloc] initWithData:datapkt protocolFamily:fam]; + NSArray* pkts = @[npkt]; return [m_Tunnel.packetFlow writePacketObjects:pkts]; } - }; class VPNPlatform final : public vpn::Platform { - NEPacketTunnelProvider * m_Tunnel; - public: - explicit VPNPlatform(NEPacketTunnelProvider * tunnel) - : m_Tunnel{tunnel} - { - } - - std::shared_ptr - ObtainInterface(vpn::InterfaceInfo) override + NEPacketTunnelProvider* const m_Tunnel; + + public: + explicit VPNPlatform(NEPacketTunnelProvider* tunnel) : m_Tunnel{tunnel} + {} + + std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override { return std::make_shared(m_Tunnel); } }; - - FrameworkContext::FrameworkContext(NEPacketTunnelProvider * tunnel) : - llarp::Context{}, - m_Tunnel{tunnel} - { - } + FrameworkContext::FrameworkContext(NEPacketTunnelProvider* tunnel) + : llarp::Context{}, m_Tunnel{tunnel} + {} void FrameworkContext::Start() { std::promise result; - m_Runner = std::make_unique( - [&result, this]() + m_Runner = std::make_unique([&result, this]() { + const RuntimeOptions opts{}; + try { - const RuntimeOptions opts{}; - try - { - Setup(opts); - Configure(llarp::Config::NetworkExtensionConfig()); - } - catch(std::exception & ) - { - result.set_exception(std::current_exception()); - return; - } - result.set_value(); - Run(opts); - }); + Setup(opts); + Configure(llarp::Config::NetworkExtensionConfig()); + } + catch (std::exception&) + { + result.set_exception(std::current_exception()); + return; + } + result.set_value(); + Run(opts); + }); auto ftr = result.get_future(); ftr.get(); @@ -154,13 +144,13 @@ namespace llarp::apple } } - struct ContextWrapper { - std::shared_ptr m_Context; -public: - explicit ContextWrapper(NEPacketTunnelProvider * tunnel) : - m_Context{std::make_shared(tunnel)} + std::unique_ptr m_Context; + + public: + explicit ContextWrapper(NEPacketTunnelProvider* tunnel) + : m_Context{std::make_unique(tunnel)} {} void @@ -176,20 +166,35 @@ public: m_Context->Wait(); } }; - +static std::string_view +DataAsStringView(NSData* data) +{ + return std::string_view{reinterpret_cast(data.bytes), data.length}; +} + +static NSData* +StringViewToData(std::string_view data) +{ + const char* ptr = data.data(); + const size_t sz = data.size(); + return [NSData dataWithBytes:ptr length:sz]; +} @implementation LLARPPacketTunnel -- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(NSError *error))completionHandler { +- (void)startTunnelWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError*))completionHandler +{ m_Context = new ContextWrapper{self}; m_Context->Start(); - completionHandler(nullptr); + [self setTunnelNetworkSettings:nullptr completionHandler:completionHandler]; } -- (void)stopTunnelWithReason:(NEProviderStopReason)reason -completionHandler:(void (^)(void))completionHandler { - if(m_Context) +- (void)stopTunnelWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler +{ + if (m_Context) { m_Context->Stop(); delete m_Context; @@ -198,5 +203,13 @@ completionHandler:(void (^)(void))completionHandler { completionHandler(); } +- (void)handleAppMessage:(NSData*)messageData + completionHandler:(void (^)(NSData* responseData))completionHandler +{ + const auto data = DataAsStringView(messageData); + LogInfo("app message: ", data); + + completionHandler(StringViewToData("ok")); +} @end diff --git a/llarp/util/logging/apple_logger.hpp b/llarp/util/logging/apple_logger.hpp new file mode 100644 index 000000000..00450b391 --- /dev/null +++ b/llarp/util/logging/apple_logger.hpp @@ -0,0 +1,32 @@ +#pragma once +#ifdef __APPLE__ +#include "logstream.hpp" + +namespace llarp +{ + struct NSLogStream : public ILogStream + { + void + PreLog( + std::stringstream& s, + LogLevel lvl, + const char* fname, + int lineno, + const std::string& nodename) const override; + + void + Print(LogLevel lvl, const char* tag, const std::string& msg) override; + + void + PostLog(std::stringstream& ss) const override; + + virtual void + ImmediateFlush() override + {} + + void Tick(llarp_time_t) override + {} + }; +} // namespace llarp + +#endif diff --git a/llarp/util/logging/apple_logger.mm b/llarp/util/logging/apple_logger.mm new file mode 100644 index 000000000..e5ca746c1 --- /dev/null +++ b/llarp/util/logging/apple_logger.mm @@ -0,0 +1,38 @@ +#ifdef __APPLE__ +#include "apple_logger.hpp" +#include "logger_internal.hpp" + +#include + +namespace llarp +{ + void + NSLogStream::PreLog( + std::stringstream& ss, + LogLevel lvl, + const char* fname, + int lineno, + const std::string& nodename) const + { + ss << "[" << LogLevelToString(lvl) << "] "; + ss << "[" << nodename << "]" + << "(" << thread_id_string() << ") " << log_timestamp() << " " << fname << ":" << lineno + << "\t"; + } + + void + NSLogStream::Print(LogLevel, const char*, const std::string& msg) + { + const char* msg_ptr = msg.c_str(); + const char* msg_fmt = "%s"; + NSString* fmt = [[NSString alloc] initWithUTF8String:msg_ptr]; + NSString* str = [[NSString alloc] initWithUTF8String:msg_fmt]; + NSLog(fmt, str); + } + + void + NSLogStream::PostLog(std::stringstream&) const + {} + +} // namespace llarp +#endif diff --git a/readme.md b/readme.md index 9122baf13..42b339e53 100644 --- a/readme.md +++ b/readme.md @@ -62,7 +62,7 @@ alternatively you can build from source, make sure you have cmake, libuv and xco $ git clone --recursive https://github.com/oxen-io/lokinet $ cd lokinet - $ ./contrib/mac.sh -DCODESIGN_KEY='insert your key identity here' + $ ./contrib/mac.sh -DCODESIGN_KEY='insert your key identity here' -DCODESIGN_TEAM_ID='team id here' ### Windows From 0bb00baacfc54c67f17f372f933c8d261d95d5c5 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 27 Jul 2021 15:43:48 -0300 Subject: [PATCH 03/45] Various cmake build cleanups/refactors - Added contrib/macos/README.txt with description of the cancer happening here. - Add provisioningprofiles that Apple wants to make things work properly - Made the entitlements files match the provisioningprofiles - Remove configured entitlements files; we *can't* change any of the things here because they are closedly tied to the provisioningprofiles -- which means if someone wants to build their own Lokinet, they have to replace a bunch of crap and change application IDs throughout. This is the hostile-to-open-source Apple way. - Remove unused old lokinet binary, as we're no longer using it on macos - Use a POST_BUILD rather than install to copy things around into the right places - Convert all the configure_file's to consistently use @ONLY - Misc cleanups --- contrib/mac.sh | 4 +- contrib/macos/LokinetExtension.Info.plist.in | 2 +- contrib/macos/README.txt | 23 +++++++ .../lokinet-extension.entitlements.plist | 32 ++++++++++ .../lokinet-extension.entitlements.plist.in | 25 -------- .../macos/lokinet-extension.provisionprofile | Bin 0 -> 13123 bytes contrib/macos/lokinet.entitlements.plist | 32 ++++++++++ contrib/macos/lokinet.entitlements.plist.in | 24 -------- contrib/macos/lokinet.provisionprofile | Bin 0 -> 13010 bytes contrib/macos/sign.sh.in | 10 ++- daemon/CMakeLists.txt | 57 +++++++++--------- llarp/CMakeLists.txt | 18 +++--- 12 files changed, 136 insertions(+), 91 deletions(-) create mode 100644 contrib/macos/README.txt create mode 100644 contrib/macos/lokinet-extension.entitlements.plist delete mode 100644 contrib/macos/lokinet-extension.entitlements.plist.in create mode 100644 contrib/macos/lokinet-extension.provisionprofile create mode 100644 contrib/macos/lokinet.entitlements.plist delete mode 100644 contrib/macos/lokinet.entitlements.plist.in create mode 100644 contrib/macos/lokinet.provisionprofile diff --git a/contrib/mac.sh b/contrib/mac.sh index 62e14802e..bfbaf712b 100755 --- a/contrib/mac.sh +++ b/contrib/mac.sh @@ -22,7 +22,7 @@ cmake \ -DFORCE_OXENMQ_SUBMODULE=ON \ -DSUBMODULE_CHECK=OFF \ -DWITH_LTO=OFF \ - -DCMAKE_INSTALL_PREFIX=$(pwd) \ -DCMAKE_BUILD_TYPE=Release \ - $@ .. + "$@" \ + .. ninja install && ninja sign diff --git a/contrib/macos/LokinetExtension.Info.plist.in b/contrib/macos/LokinetExtension.Info.plist.in index 7f6ecadbb..30dc5f8ea 100644 --- a/contrib/macos/LokinetExtension.Info.plist.in +++ b/contrib/macos/LokinetExtension.Info.plist.in @@ -21,7 +21,7 @@ lokinet CFBundleVersion - ${LOKINET_VERSION} + @LOKINET_VERSION@ ITSAppUsesNonExemptEncryption diff --git a/contrib/macos/README.txt b/contrib/macos/README.txt new file mode 100644 index 000000000..f79fd33d0 --- /dev/null +++ b/contrib/macos/README.txt @@ -0,0 +1,23 @@ +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. + + + + +These two files, in particular, are the very worst manifestations of this 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: + + lokinet.provisionprofile + lokinet-extension.provisionprofile + +This is actively hostile to open source development, but that is nothing new for Apple. + +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. diff --git a/contrib/macos/lokinet-extension.entitlements.plist b/contrib/macos/lokinet-extension.entitlements.plist new file mode 100644 index 000000000..e5dd7cbfc --- /dev/null +++ b/contrib/macos/lokinet-extension.entitlements.plist @@ -0,0 +1,32 @@ + + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider-systemextension + app-proxy-provider-systemextension + content-filter-provider-systemextension + dns-proxy-systemextension + dns-settings + + + com.apple.developer.networking.vpn.api + + allow-vpn + + + com.apple.application-identifier + SUQ8J2PCT7.com.loki-project.lokinet.network-extension + + keychain-access-groups + + SUQ8J2PCT7.* + + + com.apple.developer.team-identifier + SUQ8J2PCT7 + + + diff --git a/contrib/macos/lokinet-extension.entitlements.plist.in b/contrib/macos/lokinet-extension.entitlements.plist.in deleted file mode 100644 index 6f8dfb41b..000000000 --- a/contrib/macos/lokinet-extension.entitlements.plist.in +++ /dev/null @@ -1,25 +0,0 @@ - - - - - com.apple.developer.networking.networkextension - - packet-tunnel-provider - - - com.apple.security.network.client - - - diff --git a/contrib/macos/lokinet-extension.provisionprofile b/contrib/macos/lokinet-extension.provisionprofile new file mode 100644 index 0000000000000000000000000000000000000000..331f788e2cc8ab11a662c0a0ca6b780442097d15 GIT binary patch literal 13123 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 Co`9AB literal 0 HcmV?d00001 diff --git a/contrib/macos/lokinet.entitlements.plist b/contrib/macos/lokinet.entitlements.plist new file mode 100644 index 000000000..83675e789 --- /dev/null +++ b/contrib/macos/lokinet.entitlements.plist @@ -0,0 +1,32 @@ + + + + + + com.apple.developer.networking.networkextension + + packet-tunnel-provider-systemextension + app-proxy-provider-systemextension + content-filter-provider-systemextension + dns-proxy-systemextension + dns-settings + + + com.apple.developer.networking.vpn.api + + allow-vpn + + + com.apple.application-identifier + SUQ8J2PCT7.com.loki-project.lokinet + + keychain-access-groups + + SUQ8J2PCT7.* + + + com.apple.developer.team-identifier + SUQ8J2PCT7 + + + diff --git a/contrib/macos/lokinet.entitlements.plist.in b/contrib/macos/lokinet.entitlements.plist.in deleted file mode 100644 index 66bbbb80c..000000000 --- a/contrib/macos/lokinet.entitlements.plist.in +++ /dev/null @@ -1,24 +0,0 @@ - - - - - com.apple.developer.networking.networkextension - - packet-tunnel-provider - - - com.apple.security.network.client - - - diff --git a/contrib/macos/lokinet.provisionprofile b/contrib/macos/lokinet.provisionprofile new file mode 100644 index 0000000000000000000000000000000000000000..b6528e4535cfca157c7c48f09aa34b5be7996d78 GIT binary patch literal 13010 zcmdUWd6?VO)ptBe$esa0LPANIEI`R*Vp+DwHY5RUwq;wg<=ut?vSiD$Wy|ADwxN(r zUPv246DXvmECoVB+4m(OZz(TOwht&!^`;P2c1GMnR*Qeh+&ph_M zy1Mt=bIk8c!|o_e}mk=5d=#ikX=;+}L-P(`^Yty&xjJNxX5k6%4~ z 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 -# ) + + set(CODESIGN_KEY "" CACHE STRING "codesign the macos app using this key identity") + add_custom_target(icons ALL COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh) add_dependencies(lokinet icons lokinet-extension) - install(TARGETS lokinet-extension FRAMEWORK DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app/Contents/Frameworks" COMPONENT lokinet) + add_custom_command(TARGET lokinet + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "setting rpath" + COMMAND ${CMAKE_COMMAND} -E echo ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $ + COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $ + COMMAND mkdir -p $/Contents/Frameworks + COMMAND cp -au $ $/Contents/Frameworks/ + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.provisionprofile + $/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}.$lokinet_VERSION_MINOR}" + 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 "${CMAKE_SOURCE_DIR}/contrib/macos/Info.plist" + MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/Info.plist" MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" - MACOSX_BUNDLE_COPYRIGHT "© 2021, The Loki Project") - option(CODESIGN_KEY "codesign all the shit with this key" OFF) - if (CODESIGN_KEY AND CODESIGN_TEAM_ID) + MACOSX_BUNDLE_COPYRIGHT "© 2021, The Oxen Project") + if (CODESIGN_KEY) message(STATUS "codesigning with ${CODESIGN_KEY}") - set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/Lokinet.app") - configure_file("${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements.plist.in" - "${CMAKE_BINARY_DIR}/lokinet.entitlements.plist") - configure_file("${CMAKE_SOURCE_DIR}/contrib/macos/lokinet-extension.entitlements.plist.in" - "${CMAKE_BINARY_DIR}/lokinet-extension.entitlements.plist") - set(LOKINET_ENTITLEMENTS "${CMAKE_BINARY_DIR}/lokinet.entitlements.plist") - set(NETEXT_ENTITLEMENTS "${CMAKE_BINARY_DIR}/lokinet-extension.entitlements.plist") + set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/lokinet.app") configure_file( "${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in" - "${CMAKE_BINARY_DIR}/sign.sh") + "${PROJECT_BINARY_DIR}/sign.sh" + @ONLY) add_custom_target( sign - DEPENDS "${CMAKE_BINARY_DIR}/sign.sh" lokinet lokinet-extension - COMMAND "${CMAKE_BINARY_DIR}/sign.sh" + DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension + COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) else() - message(STATUS "will not codesign") + message(WARNING "Not codesigning: CODESIGN_KEY is not set") endif() endif() diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 6730dd0a5..a561cec07 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -272,19 +272,16 @@ if(APPLE) # god made apple so that man may suffer find_library(NETEXT NetworkExtension REQUIRED) find_library(COREFOUNDATION CoreFoundation REQUIRED) - + add_library(lokinet-extension SHARED - framework.mm - ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) - target_include_directories(lokinet-extension PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}) + framework.mm) target_link_libraries(lokinet-extension PUBLIC liblokinet ${COREFOUNDATION} ${NETEXT}) - configure_file(${CMAKE_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in - ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist) + configure_file(${PROJECT_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in + ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist @ONLY) set_target_properties(lokinet-extension PROPERTIES FRAMEWORK TRUE @@ -296,6 +293,13 @@ if(APPLE) # "compatibility version" in semantic format in Mach-O binary file SOVERSION ${lokinet_VERSION} PUBLIC_HEADER ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) + + add_custom_command(TARGET lokinet-extension + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.provisionprofile + $/Versions/Current/embedded.provisionprofile + ) + endif() From faf8a699a67614ef5a291d2150af28acd930b566 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 28 Jul 2021 11:30:42 -0300 Subject: [PATCH 04/45] Set version into Info.plist, don't manually configure cmake already treats the info plist as a file to be configured (not merely copied) so we don't need to configure_file ourselves to a temp file. --- CMakeLists.txt | 6 ++++++ contrib/macos/{Info.plist => Info.plist.in} | 4 ++-- daemon/CMakeLists.txt | 2 +- llarp/CMakeLists.txt | 5 +---- 4 files changed, 10 insertions(+), 7 deletions(-) rename contrib/macos/{Info.plist => Info.plist.in} (87%) diff --git a/CMakeLists.txt b/CMakeLists.txt index aa6fc1290..3a72a1b8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,12 @@ project(lokinet DESCRIPTION "lokinet - IP packet onion router" LANGUAGES ${LANGS}) +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) +endif() + set(RELEASE_MOTTO "A Series of Tubes" CACHE STRING "Release motto") add_definitions(-DLLARP_VERSION_MAJOR=${lokinet_VERSION_MAJOR}) diff --git a/contrib/macos/Info.plist b/contrib/macos/Info.plist.in similarity index 87% rename from contrib/macos/Info.plist rename to contrib/macos/Info.plist.in index d39aed3a8..5e09e839b 100644 --- a/contrib/macos/Info.plist +++ b/contrib/macos/Info.plist.in @@ -17,8 +17,8 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 0.1 + @LOKINET_VERSION@ CFBundleVersion - 0.1 + @LOKINET_VERSION@.@LOKINET_APPLE_BUILD@ diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 39f1b1acd..724c14513 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -97,7 +97,7 @@ if(APPLE) 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" + MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/Info.plist.in" MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" MACOSX_BUNDLE_COPYRIGHT "© 2021, The Oxen Project") if (CODESIGN_KEY) diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index a561cec07..ba47b0e68 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -280,14 +280,11 @@ if(APPLE) ${COREFOUNDATION} ${NETEXT}) - configure_file(${PROJECT_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in - ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist @ONLY) - set_target_properties(lokinet-extension PROPERTIES FRAMEWORK TRUE FRAMEWORK_VERSION ${lokinet_VERSION} MACOSX_FRAMEWORK_IDENTIFIER com.loki-project.lokinet.network-extension - MACOSX_FRAMEWORK_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/LokinetExtension.Info.plist + MACOSX_FRAMEWORK_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in # "current version" in semantic format in Mach-O binary file VERSION ${lokinet_VERSION} # "compatibility version" in semantic format in Mach-O binary file From 3ab117a03b54bf7ecfa6603fc11fd8473a9f9690 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 29 Jul 2021 14:09:18 -0300 Subject: [PATCH 05/45] Switch extension from a framework to an appex --- contrib/macos/README.txt | 25 +++++++++++--- .../lokinet-extension.entitlements.plist | 31 ++++++++---------- .../macos/lokinet-extension.provisionprofile | Bin 13123 -> 17274 bytes contrib/macos/lokinet.entitlements.plist | 24 ++++---------- contrib/macos/lokinet.provisionprofile | Bin 13010 -> 17016 bytes contrib/macos/sign.sh.in | 6 ++-- daemon/CMakeLists.txt | 18 ++++------ daemon/lokinet.swift | 7 ++-- llarp/CMakeLists.txt | 24 +++++++------- llarp/framework.mm | 2 ++ 10 files changed, 70 insertions(+), 67 deletions(-) diff --git a/contrib/macos/README.txt b/contrib/macos/README.txt index f79fd33d0..9880ecc3c 100644 --- a/contrib/macos/README.txt +++ b/contrib/macos/README.txt @@ -4,18 +4,33 @@ into the no-CI, no-help, undocumented, non-toy-apps-need-not-apply modern Apple This is disgusting. +But it gets worse. - - -These two files, in particular, are the very worst manifestations of this 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: +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 diff --git a/contrib/macos/lokinet-extension.entitlements.plist b/contrib/macos/lokinet-extension.entitlements.plist index e5dd7cbfc..8233a7926 100644 --- a/contrib/macos/lokinet-extension.entitlements.plist +++ b/contrib/macos/lokinet-extension.entitlements.plist @@ -2,31 +2,28 @@ - - com.apple.developer.networking.networkextension - - packet-tunnel-provider-systemextension - app-proxy-provider-systemextension - content-filter-provider-systemextension - dns-proxy-systemextension - dns-settings - - - com.apple.developer.networking.vpn.api - - allow-vpn - - com.apple.application-identifier SUQ8J2PCT7.com.loki-project.lokinet.network-extension - keychain-access-groups + com.apple.developer.networking.networkextension - SUQ8J2PCT7.* + packet-tunnel-provider com.apple.developer.team-identifier SUQ8J2PCT7 + com.apple.security.app-sandbox + + + com.apple.security.get-task-allow + + + com.apple.security.network.client + + + com.apple.security.network.server + + diff --git a/contrib/macos/lokinet-extension.provisionprofile b/contrib/macos/lokinet-extension.provisionprofile index 331f788e2cc8ab11a662c0a0ca6b780442097d15..71f066bda46e4ac64927e6331401cc3b0b627844 100644 GIT binary patch delta 9710 zcmeHtYs~!ESzrH~Z0II!vSF8yY_efY6T%-b`A6m76s!YZ`H)L*<><5(Yf^0ET=3 z!>>Pc=Tm3MplNDZ#AGK@WGt%EQm;Ct2{)!d*Ui3fXLXV@q)f%xKFPK`(Lofc)*Q)D zuw<&88as@ostm(4R3K2bt5a(qo!71q?p)rCHQqv8`*aL=s~5R>?(-bv*+d)k6yvVv z*I#<*ZI3P`GUG|uWa+M>wL!Xm>*Mb~Q`nj@#FNCRy~41)%&4%GSC_H=C1Y0A#cpuo zQ_`X0YMyPqc{Ubnmt-l1+_|QqVp^*4dgi*40hUJIvzNPPFYB&dU>DK(w$+AA73&2z zoP7j~%_7WK(Pfn5DxSB5VvaPpIgls*oZ`u8V~z}d)Q;x6VkufvRzy}iyj)I2 z+?tWQU3Ri4)tuTDxo54eXe2nE97fnQKE~RLj~!aZmX;6qN<5tuCtP(Mmd0wP0x%cQ2!RcZ*+eFaV>s4>RT9CfV z1bsa0jMA>{!pg_UfJ~>ZtLJd034(_m`0Z$7E>(=_yd>qLzN}NKqvH5L#Vkju0SF*1lX$UPs*bqm9185B zAdw4Rv=b;4$jP!N-j#yrfPx-RZlelMeFQp&XqW{>Ff0o#57O)Z{AS{ehKSa?gVf0v zLpAIYNTEpT;JewyF{@qtg;AaPqH@LL7=j%&DM=K@;KRJgD6mMHYT}-%;Y*a}iC@UM z$P=w7XqC5?Vh6GMkk1RxmXi=fwo_)YW1n$c6sRO9HC*JmAwaFhy*zBoU;z{aygmgf z;plED$OHcr@=5M*!Sf(hTqbggQ!Wbf<+;pR&ol6{JSgA+%+FTd+dlVK=s@+3cWY|0+_i7?(z1$48o z#~RTy_Te}>*hGxi$tJ_$EsdxWpZPR3-Xp`VV)>ck9Aw-|DxV)(1Torz)aS=BYfnl@ z)7^C39ER?sqxLBcOrA*elF68@yM%IoF3sX|hvlLkAkCok`;k0w&a5Qx1+P_ALZnEs zvx*8{GWiGF$=E<_ghX@09uu`$+CsS{(H^s5>kF8`=<#1f{9__1#(P_j_Xy8@T z*px);AS_HY%TMNRv1dkhm=$cSZpYeL%A84p$G97T*G9>(I1E}K9OR>5#v{k*aZZ^O zYq!+cNKNB@u}0gXNm0sn=j5s^lIhkgS!vcPW8esJ3k}egkCd$X&S%G=*LWX#?IVvo zd-DZ^1J@51&{OV%o=YZMMO({yg4xSSc@i0CsbhaGsCWH4554360eI#K0Nx-C*^2=0 zMPoOB$Nt{{&yg7ul2cic2iKMiwF9wu3()j^fPMwQvx+kaQQEcT!wt|ei6`frVlg6W zF!7%~&}E!;7wGQc-1%;4@ybAl>fubQ%vs~p9xXMkv^^+ww`l^+B=K@l_WeG#4vZNo z@}SAfqb@IUIhtxPF^dptW5WvD#~_6YlZjKzV#7@v6~b2jnau{=_2Y>r z@RJiXvx6$(h21i6%egyS<9u^qdR3gsvn5^!d7^Ebw4!s3TPvf3I@h#WxET%fWP6eh z*j%c#fy!o8X4koY+*ApZ1O#wg;yB0_*1|hDm|HuRuBz?crlQrNJg*H|D2;d#@ds+p z!#*LW$H4M-W6oy#^$GQOd|E2{iPsru)1@`VFA_iv~K~TlwSd zsh^%En!$>Uzi%2mBJr^}`m+MM_ngylD(@ZL9q*iMS%x*r&sSxH=-70yB3i7*xVh?fwl(v!zODsUz>V>GBhnE!-Db0$ z870;jQx;jaU*%}2#&yJEBx0Rg*J~zYKDO!|g8Q(XD|pp*oT4pFO0=_S&Wntz7l!R@ zCeEA_9a@|$f|V|XmUF~+R7;lx!A`w=?-P+$(#LkBG74|g^mu5PM%fL%=aC_jpzn$poyZi+0+cyyAH06V>AOV;>^P+z%Z$a?Fn>X z3!JRCcy0pG6KEf8*>TCRiBy;8xu;`eO)leuXfgEF^_~DY{odNL$UNrXq1Ms->ryZk|d{OTG!kP1MRXdjyb=ZL#-K@1r`@FXXt6-HKD27=jl1=X$eQBwy?*YkI$dxD zvoxm65PK!PI%pB;hbvDQk=MWbEsr68$_`FWDL~9Ld-;S3am-<+!N{D{?t_D?(tC@u zUDU-ks%cETaz>X*iyJEzcVxNUQytP7^I}CuhiowARAn$BlEg?zIC14qd$~W+{wk#m z(I=ddY7-}}#`x-N#~{{#U6Hz5w&-iCW6EL+(`p|C6KzZIL(`2sd?Ot zve%0yZFVbc2kkRh+=m=9AN0Ahb8{_J(!+og3r#|e*>ca+E$w8`oeUwpIf%HI!$B=9stF`2a?BeS2;cmbBFTbQt= zDQwl7tZd2yxnW40iv(&H6t`4{1}Icl3uGx3J9!Xs$#4L#rowhgZW$_6gMt7g%_-OT zd&&atd@sG4w?d~GsrHJS*cS@jZ&Dnkqil! zbO=@lbyylXB@c0oG&o3@#C{%pRm|Y%>z>*1EKf_L_*vYce12`PnJ8%m$SSvyIi5KF)c3g9Z~a31lR- z0eea=X(EQ_iQABNefGD)yoy_`A_BnM@eV_tIKR|(A%D8dRLPfd{z4|zfYaLyl*`;u zWKip@sm|xkyVpFu^;N9#Y`}7XIlzABLEOPFajpJ_Q)~hAeeiS`y&TjY5CG7!xPPcE zV85XdA$qTe^9XQret9`a3{dW@v_!7|==D#7f_kl?fbs{#K>{2HA1=NoahSvwTo=&r zWnL`OZ?4G2AYjNE1X>&NfNrPZi?2e!_nV7jfV00a?Gjf~iGwsbxDSOk-nw@8lKZr+ z0SVzU=i9*KAVOUpAC_wwcpr$;A_QIv4CH}v`e~9!Y#12I>Vc?}qQR`mZ7P=~&{5CXZ~na_qca+FT0w(E*rLg5|=2 zAazXKNiW@RY!A|wxVrGPnFP)foHrm0NmZn28s)}fs-MjEjg~}KfQ|&YOu`7jC^FZd zdh~^7ZsZW)f^;f?6g>#saDisGnvPqSdDpFKz9%5A`#aP~w zr0z`g8KDY`Z0btepkfWch^qNU;3^0|p_FPP>NMZQ<{psC(=~))(6kP;r8OqB5h4}y zu#XDXhGv~{;yiK%J2u(pggUDYH56EMefB^pxAq4vnCfj9_2d*;<|blI+#R#i=#)>@ z6fBK`ZrExjR&9#Xr?osuY(^1_y}l^I$> zIwtUPFIAp<7;2G$=L4M0T&U#_oBdX@$dqc_s#5z#m0@-akV6_Z;x648a*H9T$4$db zm?g%XI2NK)syKZLeUNb~Mu{DA6m9Em49{dFGB*6s11~P@n$#{T*K-H-^ zi2U3|=YXxhI6M#mbP~FL>ap-_8>I14@3^;LfGFx@nj}@;n`pL=BAYoOC~`H?0V5?_ zjGO6oVS4j&((BX+J6aAy3|p_QU9F$B)1l3PGDESDHnX>0Q_Z{G+&ScU>>dsDjVN#yM2m}S zqEM8>UjNLSpFF>^tAZG+O21hAsKv@FP>cxfcoyd&`m%xKFG9@i$Q7EVV$oA~E zEJ2=uN!j%mxDN9SzeWAH0sB5v^BFcjq~26WH;ll}(S3PNtCHBG0WI!pAX2W6TKp!0H-jmzIGD7{2b^-zigH0#AZ zVVCCC7LYuE#@hR+ySvHu1t?K^puF9!j6jg=+}m;lXwB+#m@=A58bos1KHbmxJ*eHP zuBI_1Hmhv`s~e@s)hgLL%gW?sk~%hRL1AWCb#Az5y!{f?a;T;yo3IJ18j!)gRP%cv z*P1i1QQY$S7ao2$9c9r(5i4uX##^mMM(L@_qCo{Gnsw@ngush0%LaK#^Dpyd>-y=} zyzk5bfRz)O0Z)j$eJeqNLe~MH?9|{B-!Ftg3B-XwpGrdZV5Uw4J^)D`{K~4{Md=Iq zS?m-*tOIxoM7TWSF%`%7mc$sUNMwnSp=cPkz1CWVZ>O0r#&~z7F3{tx`vjaYU*Rok_iRpfaHM6aJFHx zVQG=JVN7Tit6hcEe1j?5oC$lp50*T!-K>y_l62*cCP4gn<>gO5 z_Csfo=2z=D2{PnpfS3k+P#z~)Ou4EAfC;D`3!0i3mme`a_@M=@N+mk99@?C0oCy&$rChHa&}ltwAxX_Iu1-SiAV50kT~(hFP}5Rnd2l- z%inuZas;aZX@t4^;@iJP0ERS3A<%98bJNR#0x9OeSinQs2Puaa-T}}h2v#E<$9GGUSDk4*EGncjp z+}pRC4bveza<$OFuS2#gW}1wKewNLy(I@Tq)qUMW#Z`1_qO#sr<@>i~-FSKa>^O`1 z8`ZHnw9)wb=iffQ{`*f}UH|VVzxn#9w_kzJo34N1$v0iDkA!7?wL4U&{$}(?-cEda z{%y-UZ$ywQXnKXb=m$GL_SEQAVRXFyji=su{l`ze<&h|4qT@D*>g!*>^Tc1rXoz6Q z+3X5N3HS=9G4zTcr?V>#VrMu9kr>25&yMTnur1>o%kF-iAlMY0Oz5jA1x>DSmV>WI z2%@hzVur#KWCl$s_`16D#5MkofBGtPf?xmpcf9A_*d`!gd=p+xLkzmYqHuQQPp95h z2t^R$5eSUT&`-bXo!%R+2zY`a816#vy8n};M_vuT>D7-v`g=c(|5o+e!v|jY!)Jcv z=`Z@KDOHa&(kOWWcv8;7N7s6-+8_N;eYvypZLmKet7%6?3W%+zPS9GKliyWO27Kh z2jBJ?|1EF&@b?X`+qdg4bol50)f?^eZcw zalZ2t*ZB{&`p^H$-#Y)hKmHFt^zHxU*~NR&uRiwK^H)FnFU0S8eH}mjp6~eVxBlDq zOTYGs4?g+JUtYZBdGSNz?495G9lzY;@B8RKTmHef{lh1I?OEnG*8h?Cl|Ov^NB_a+ zp8H2HeB|8xlaGD=OCSHozxnR;D{pu~_`&}r8UN<5o~) d7yjT4-}e(={+S>9oczx}_x+DP^!MKTe*i3Fw<7=m delta 5898 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 diff --git a/contrib/macos/lokinet.entitlements.plist b/contrib/macos/lokinet.entitlements.plist index 83675e789..155d265ba 100644 --- a/contrib/macos/lokinet.entitlements.plist +++ b/contrib/macos/lokinet.entitlements.plist @@ -2,31 +2,21 @@ - - com.apple.developer.networking.networkextension - - packet-tunnel-provider-systemextension - app-proxy-provider-systemextension - content-filter-provider-systemextension - dns-proxy-systemextension - dns-settings - - - com.apple.developer.networking.vpn.api - - allow-vpn - - com.apple.application-identifier SUQ8J2PCT7.com.loki-project.lokinet - keychain-access-groups + com.apple.developer.networking.networkextension - SUQ8J2PCT7.* + packet-tunnel-provider com.apple.developer.team-identifier SUQ8J2PCT7 + com.apple.security.app-sandbox + + + com.apple.security.get-task-allow + diff --git a/contrib/macos/lokinet.provisionprofile b/contrib/macos/lokinet.provisionprofile index b6528e4535cfca157c7c48f09aa34b5be7996d78..f740cd98a782e2dc35dc4fac71a9da6e29a5809a 100644 GIT binary patch literal 17016 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 OPxj7>e(Tj$_xvBCZ)^(y delta 6101 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 diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in index 9e906dba1..b05a06e2a 100755 --- a/contrib/macos/sign.sh.in +++ b/contrib/macos/sign.sh.in @@ -1,10 +1,10 @@ #!/usr/bin/env bash set -e -codesign --verbose=4 --force -s "@CODESIGN_KEY@" \ +codesign --verbose=4 --force -s "@CODESIGN_DEV@" \ --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-extension.entitlements.plist" \ - --deep --strict --timestamp --options=runtime "@SIGN_TARGET@/Contents/Frameworks/lokinet-extension.framework" + --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_KEY@" \ + codesign --verbose=4 --force -s "@CODESIGN_APP@" \ --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet.entitlements.plist" \ --deep --strict --timestamp --options=runtime "$file" done diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 724c14513..cd9e9c200 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,9 +1,7 @@ if(APPLE) set(LOKINET_SWIFT_SOURCES lokinet.swift) add_executable(lokinet ${LOKINET_SWIFT_SOURCES}) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) - target_link_libraries(lokinet PUBLIC lokinet-extension) else() add_executable(lokinet lokinet.cpp) add_executable(lokinet-vpn lokinet-vpn.cpp) @@ -71,7 +69,8 @@ endforeach() if(APPLE) - set(CODESIGN_KEY "" CACHE STRING "codesign the macos app using this key identity") + set(CODESIGN_APP "" CACHE STRING "codesign the macos app using this key identity") + set(CODESIGN_DEV "" CACHE STRING "codesign the internal extension using this key identity") add_custom_target(icons ALL COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns @@ -79,11 +78,8 @@ if(APPLE) add_dependencies(lokinet icons lokinet-extension) add_custom_command(TARGET lokinet POST_BUILD - COMMAND ${CMAKE_COMMAND} -E echo "setting rpath" - COMMAND ${CMAKE_COMMAND} -E echo ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $ - COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $ - COMMAND mkdir -p $/Contents/Frameworks - COMMAND cp -au $ $/Contents/Frameworks/ + COMMAND mkdir -p $/Contents/PlugIns + COMMAND cp -au $ $/Contents/PlugIns/ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.provisionprofile $/Contents/embedded.provisionprofile ) @@ -100,8 +96,8 @@ if(APPLE) MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/Info.plist.in" MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" MACOSX_BUNDLE_COPYRIGHT "© 2021, The Oxen Project") - if (CODESIGN_KEY) - message(STATUS "codesigning with ${CODESIGN_KEY}") + if (CODESIGN_APP AND CODESIGN_DEV) + message(STATUS "codesigning with ${CODESIGN_APP} (app) ${CODESIGN_DEV} (appex)") set(SIGN_TARGET "${CMAKE_CURRENT_BINARY_DIR}/lokinet.app") configure_file( "${PROJECT_SOURCE_DIR}/contrib/macos/sign.sh.in" @@ -113,7 +109,7 @@ if(APPLE) COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) else() - message(WARNING "Not codesigning: CODESIGN_KEY is not set") + message(WARNING "Not codesigning: CODESIGN_APP (=${CODESIGN_APP}) and/or CODESIGN_DEV (=${CODESIGN_DEV}) are not set") endif() endif() diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift index b80c01227..564cbf62a 100644 --- a/daemon/lokinet.swift +++ b/daemon/lokinet.swift @@ -36,13 +36,16 @@ class LokinetMain: NSObject, NSApplicationDelegate { } } let providerProtocol = NETunnelProviderProtocol() - providerProtocol.serverAddress = "" + providerProtocol.serverAddress = "loki.loki" // Needs to be set to some non-null dummy value providerProtocol.username = "anonymous" providerProtocol.providerBundleIdentifier = self.lokinetComponent - providerProtocol.includeAllNetworks = 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. + providerProtocol.includeAllNetworks = false self.vpnManager.protocolConfiguration = providerProtocol self.vpnManager.isEnabled = true self.vpnManager.isOnDemandEnabled = true + self.vpnManager.localizedDescription = "lokinet" self.vpnManager.saveToPreferences(completionHandler: { error -> Void in if error != nil { NSLog("Error saving to preferences") diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index ba47b0e68..a07c8b70d 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -273,28 +273,28 @@ if(APPLE) find_library(NETEXT NetworkExtension REQUIRED) find_library(COREFOUNDATION CoreFoundation REQUIRED) - add_library(lokinet-extension SHARED - framework.mm) + add_executable(lokinet-extension MACOSX_BUNDLE framework.mm) target_link_libraries(lokinet-extension PUBLIC liblokinet ${COREFOUNDATION} ${NETEXT}) set_target_properties(lokinet-extension PROPERTIES - FRAMEWORK TRUE - FRAMEWORK_VERSION ${lokinet_VERSION} - MACOSX_FRAMEWORK_IDENTIFIER com.loki-project.lokinet.network-extension - MACOSX_FRAMEWORK_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetExtension.Info.plist.in - # "current version" in semantic format in Mach-O binary file - VERSION ${lokinet_VERSION} - # "compatibility version" in semantic format in Mach-O binary file - SOVERSION ${lokinet_VERSION} - PUBLIC_HEADER ${CMAKE_SOURCE_DIR}/include/lokinet-extension.hpp) + 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 + ) + + # Not sure what -fapplication-extension does, but XCode puts it in so... + # -e _NSExtensionMain because it has that instead of a `main` function entry point, of course. + target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain) + target_compile_options(lokinet-extension PRIVATE -fapplication-extension) add_custom_command(TARGET lokinet-extension POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.provisionprofile - $/Versions/Current/embedded.provisionprofile + $/Contents/embedded.provisionprofile ) diff --git a/llarp/framework.mm b/llarp/framework.mm index 032c2424a..32cde8978 100644 --- a/llarp/framework.mm +++ b/llarp/framework.mm @@ -186,6 +186,7 @@ StringViewToData(std::string_view data) - (void)startTunnelWithOptions:(NSDictionary*)options completionHandler:(void (^)(NSError*))completionHandler { + NSLog(@"OMG startTunnelWithOptions"); m_Context = new ContextWrapper{self}; m_Context->Start(); [self setTunnelNetworkSettings:nullptr completionHandler:completionHandler]; @@ -194,6 +195,7 @@ StringViewToData(std::string_view data) - (void)stopTunnelWithReason:(NEProviderStopReason)reason completionHandler:(void (^)(void))completionHandler { + NSLog(@"STOP TUNNEL"); if (m_Context) { m_Context->Stop(); From 81d27c35c16893368109693fc0029fc8586a4570 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 29 Jul 2021 14:26:12 -0300 Subject: [PATCH 06/45] Default CODESIGN_APPEX to CODESIGN_APP Sometimes (e.g. dev builds) these can apparently be the same; sometimes it seems they need to be different, because Apple. --- contrib/mac.sh | 17 ++++++++++++++--- contrib/macos/sign.sh.in | 2 +- daemon/CMakeLists.txt | 8 ++++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/contrib/mac.sh b/contrib/mac.sh index bfbaf712b..38070ba96 100755 --- a/contrib/mac.sh +++ b/contrib/mac.sh @@ -1,11 +1,18 @@ #!/bin/bash # -# build the shit on mac -# t. jeff +# Build the shit on mac +# +# You will generally need to add: -DCODESIGN_APP=... to make this work, and (unless you are a +# lokinet team member) will need to pay Apple money for your own team ID and arse around with +# provisioning profiles. See macos/README.txt. # set -e set +x +if ! [ -f LICENSE.txt ] || ! [ -d llarp ]; then + echo "You need to run this as ./contrib/mac.sh from the top-level lokinet project directory" +fi + mkdir -p build-mac cd build-mac cmake \ @@ -25,4 +32,8 @@ cmake \ -DCMAKE_BUILD_TYPE=Release \ "$@" \ .. -ninja install && ninja sign +ninja sign + +echo -e "Build complete, your app is here:\n" +ls -lad daemon/lokinet.app +echo "" diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in index b05a06e2a..6ebf0859a 100755 --- a/contrib/macos/sign.sh.in +++ b/contrib/macos/sign.sh.in @@ -1,6 +1,6 @@ #!/usr/bin/env bash set -e -codesign --verbose=4 --force -s "@CODESIGN_DEV@" \ +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 diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index cd9e9c200..10f509bbc 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -70,7 +70,7 @@ endforeach() if(APPLE) set(CODESIGN_APP "" CACHE STRING "codesign the macos app using this key identity") - set(CODESIGN_DEV "" CACHE STRING "codesign the internal extension 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") add_custom_target(icons ALL COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns @@ -96,8 +96,8 @@ if(APPLE) MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/contrib/macos/Info.plist.in" MACOSX_BUNDLE_ICON_FILE "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" MACOSX_BUNDLE_COPYRIGHT "© 2021, The Oxen Project") - if (CODESIGN_APP AND CODESIGN_DEV) - message(STATUS "codesigning with ${CODESIGN_APP} (app) ${CODESIGN_DEV} (appex)") + 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" @@ -109,7 +109,7 @@ if(APPLE) COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) else() - message(WARNING "Not codesigning: CODESIGN_APP (=${CODESIGN_APP}) and/or CODESIGN_DEV (=${CODESIGN_DEV}) are not set") + message(WARNING "Not codesigning: CODESIGN_APP (=${CODESIGN_APP}) and/or CODESIGN_APPEX (=${CODESIGN_APPEX}) are not set") endif() endif() From 7db24594690b56485f7bed45a03d6c0d72a4906c Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 29 Jul 2021 16:40:25 -0400 Subject: [PATCH 07/45] macos sort of works now --- CMakeLists.txt | 2 +- contrib/macos/LokinetDNSProxy.Info.plist.in | 40 +++++ .../macos/lokinet-dnsproxy.entitlements.plist | 29 ++++ .../macos/lokinet-dnsproxy.provisionprofile | Bin 0 -> 17128 bytes contrib/macos/lokinet.entitlements.plist | 9 + contrib/macos/sign.sh.in | 3 + daemon/CMakeLists.txt | 17 +- daemon/lokinet.swift | 72 +++++++- include/lokinet-dnsproxy.hpp | 19 +++ llarp/CMakeLists.txt | 42 ++++- llarp/apple.hpp | 40 +++++ llarp/config/config.cpp | 1 - llarp/dns/message.cpp | 27 +++ llarp/dns/message.hpp | 9 +- llarp/dns/question.cpp | 14 ++ llarp/dns/question.hpp | 6 + llarp/dns/rr.cpp | 19 +++ llarp/dns/rr.hpp | 5 + llarp/dns/serialize.hpp | 6 +- llarp/dnsproxy.mm | 154 ++++++++++++++++++ llarp/ev/ev_libuv.cpp | 4 +- llarp/framework.mm | 123 +++++++++----- llarp/handlers/tun.cpp | 2 +- llarp/rpc/rpc_server.cpp | 42 +++++ 24 files changed, 619 insertions(+), 66 deletions(-) create mode 100644 contrib/macos/LokinetDNSProxy.Info.plist.in create mode 100644 contrib/macos/lokinet-dnsproxy.entitlements.plist create mode 100644 contrib/macos/lokinet-dnsproxy.provisionprofile create mode 100644 include/lokinet-dnsproxy.hpp create mode 100644 llarp/apple.hpp create mode 100644 llarp/dnsproxy.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a72a1b8c..af550c638 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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)") set(LANGS ASM C CXX) if(APPLE) diff --git a/contrib/macos/LokinetDNSProxy.Info.plist.in b/contrib/macos/LokinetDNSProxy.Info.plist.in new file mode 100644 index 000000000..522b476ec --- /dev/null +++ b/contrib/macos/LokinetDNSProxy.Info.plist.in @@ -0,0 +1,40 @@ + + + + + CFBundleDisplayName + Lokinet + + CFBundleExecutable + lokinet-dnsproxy + + CFBundleIdentifier + com.loki-project.lokinet.dns-proxy + + CFBundleInfoDictionaryVersion + 6.0 + + CFBundlePackageType + XPC! + + CFBundleName + lokinet + + CFBundleVersion + @LOKINET_VERSION@ + + ITSAppUsesNonExemptEncryption + + + LSMinimumSystemVersion + 11.0 + + NSExtension + + NSExtensionPointIdentifier + com.apple.networkextension.dns-proxy + NSExtensionPrincipalClass + DNSProvider + + + diff --git a/contrib/macos/lokinet-dnsproxy.entitlements.plist b/contrib/macos/lokinet-dnsproxy.entitlements.plist new file mode 100644 index 000000000..fa43bbd2b --- /dev/null +++ b/contrib/macos/lokinet-dnsproxy.entitlements.plist @@ -0,0 +1,29 @@ + + + + + com.apple.application-identifier + SUQ8J2PCT7.com.loki-project.lokinet.dns-proxy + + com.apple.developer.networking.networkextension + + dns-proxy + + + com.apple.developer.team-identifier + SUQ8J2PCT7 + + com.apple.security.app-sandbox + + + com.apple.security.get-task-allow + + + com.apple.security.network.client + + + com.apple.security.network.server + + + + diff --git a/contrib/macos/lokinet-dnsproxy.provisionprofile b/contrib/macos/lokinet-dnsproxy.provisionprofile new file mode 100644 index 0000000000000000000000000000000000000000..87cd403bb4919366f2e767f28b38cb0f168a60c0 GIT binary patch literal 17128 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 Z?Z9=CJE$b@rw5OI`eOO=&%e0*zX6(qnR);K literal 0 HcmV?d00001 diff --git a/contrib/macos/lokinet.entitlements.plist b/contrib/macos/lokinet.entitlements.plist index 155d265ba..3869f5b04 100644 --- a/contrib/macos/lokinet.entitlements.plist +++ b/contrib/macos/lokinet.entitlements.plist @@ -8,6 +8,8 @@ com.apple.developer.networking.networkextension packet-tunnel-provider + dns-proxy + dns-settings com.apple.developer.team-identifier @@ -18,5 +20,12 @@ com.apple.security.get-task-allow + + com.apple.security.network.client + + + com.apple.security.network.server + + diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in index 6ebf0859a..af3d18d55 100755 --- a/contrib/macos/sign.sh.in +++ b/contrib/macos/sign.sh.in @@ -3,6 +3,9 @@ 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" +codesign --verbose=4 --force -s "@CODESIGN_APPEX@" \ + --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-dnsproxy.entitlements.plist" \ + --deep --strict --timestamp --options=runtime "@SIGN_TARGET@/Contents/PlugIns/lokinet-dnsproxy.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" \ diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 10f509bbc..ac0598f74 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,14 +1,17 @@ + +add_executable(lokinet-vpn lokinet-vpn.cpp) if(APPLE) set(LOKINET_SWIFT_SOURCES lokinet.swift) add_executable(lokinet ${LOKINET_SWIFT_SOURCES}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) else() add_executable(lokinet lokinet.cpp) - add_executable(lokinet-vpn lokinet-vpn.cpp) add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) enable_lto(lokinet lokinet-vpn lokinet-bootstrap) endif() + if(TRACY_ROOT) target_sources(lokinet PRIVATE ${TRACY_ROOT}/TracyClient.cpp) endif() @@ -38,9 +41,9 @@ if(NOT APPLE) endif() endif() -set(exetargets lokinet) +set(exetargets lokinet lokinet-vpn) if(NOT APPLE) - list(APPEND exetargets lokinet-vpn lokinet-bootstrap) + list(APPEND exetargets lokinet-bootstrap) endif() foreach(exe ${exetargets}) @@ -76,10 +79,14 @@ if(APPLE) COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns DEPENDS ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh) add_dependencies(lokinet icons lokinet-extension) + file(DOWNLOAD "https://seed.lokinet.org/lokinet.signed" ${CMAKE_CURRENT_BINARY_DIR}/bootstrap.signed) add_custom_command(TARGET lokinet POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/bootstrap.signed + $/Contents/Resources/bootstrap.signed COMMAND mkdir -p $/Contents/PlugIns - COMMAND cp -au $ $/Contents/PlugIns/ + COMMAND cp -a $ $/Contents/PlugIns/ + COMMAND cp -a $ $/Contents/PlugIns/ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.provisionprofile $/Contents/embedded.provisionprofile ) @@ -105,7 +112,7 @@ if(APPLE) @ONLY) add_custom_target( sign - DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension + DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension lokinet-dnsproxy COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) else() diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift index 564cbf62a..a12c1da79 100644 --- a/daemon/lokinet.swift +++ b/daemon/lokinet.swift @@ -8,7 +8,7 @@ let app = NSApplication.shared class LokinetMain: NSObject, NSApplicationDelegate { var vpnManager = NETunnelProviderManager() let lokinetComponent = "com.loki-project.lokinet.network-extension" - var lokinetAdminTimer: DispatchSourceTimer? + var dnsComponent = "com.loki-project.lokinet.dns-proxy" func applicationDidFinishLaunching(_: Notification) { setupVPNJizz() @@ -18,12 +18,67 @@ class LokinetMain: NSObject, NSApplicationDelegate { app.terminate(self) } + func setupDNSJizz() { + NSLog("setting up dns settings") + let dns = NEDNSSettingsManager.shared() + let settings = NEDNSSettings(servers: ["172.16.0.1"]) + dns.dnsSettings = settings + dns.loadFromPreferences { [self] (error: Error?) -> Void in + if let error = error { + NSLog(error.localizedDescription) + bail() + return + } + dns.saveToPreferences { [self] (error: Error?) -> Void in + if let error = error { + NSLog(error.localizedDescription) + bail() + return + } + NSLog("dns setting set up probably") + } + } + } + + func setupDNSProxyJizz() { + NSLog("setting up dns proxy") + let dns = NEDNSProxyManager.shared() + let provider = NEDNSProxyProviderProtocol() + provider.providerBundleIdentifier = dnsComponent + provider.username = "Anonymous" + provider.serverAddress = "loki.loki" + provider.includeAllNetworks = true + provider.enforceRoutes = true + dns.providerProtocol = provider + dns.localizedDescription = "lokinet dns" + dns.loadFromPreferences { [self] (error: Error?) -> Void in + if let error = error { + NSLog(error.localizedDescription) + bail() + return + } + provider.includeAllNetworks = true + provider.enforceRoutes = true + dns.isEnabled = true + dns.saveToPreferences { [self] (error: Error?) -> Void in + if let error = error { + NSLog(error.localizedDescription) + bail() + return + } + self.initDNSObserver() + NSLog("dns is up probably") + } + } + } + func setupVPNJizz() { NSLog("Starting up lokinet") NETunnelProviderManager.loadAllFromPreferences { [self] (savedManagers: [NETunnelProviderManager]?, error: Error?) in if let error = error { NSLog(error.localizedDescription) bail() + return } if let savedManagers = savedManagers { @@ -44,7 +99,10 @@ class LokinetMain: NSObject, NSApplicationDelegate { providerProtocol.includeAllNetworks = false self.vpnManager.protocolConfiguration = providerProtocol self.vpnManager.isEnabled = true - self.vpnManager.isOnDemandEnabled = true + // self.vpnManager.isOnDemandEnabled = true + let rules = NEAppRule() + rules.matchDomains = ["*.snode", "*.loki"] + self.vpnManager.appRules = [rules] self.vpnManager.localizedDescription = "lokinet" self.vpnManager.saveToPreferences(completionHandler: { error -> Void in if error != nil { @@ -76,6 +134,13 @@ class LokinetMain: NSObject, NSApplicationDelegate { } } + func initDNSObserver() { + NotificationCenter.default.addObserver(forName: NSNotification.Name.NEDNSProxyConfigurationDidChange, object: NEDNSProxyManager.shared(), queue: OperationQueue.main) { _ -> Void in + let dns = NEDNSProxyManager.shared() + NSLog("%@", dns) + } + } + func initializeConnectionObserver() { NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: vpnManager.connection, queue: OperationQueue.main) { _ -> Void in if self.vpnManager.connection.status == .invalid { @@ -88,6 +153,9 @@ class LokinetMain: NSObject, NSApplicationDelegate { NSLog("VPN is reasserting...") } else if self.vpnManager.connection.status == .disconnecting { NSLog("VPN is disconnecting...") + } else if self.vpnManager.connection.status == .connected { + NSLog("VPN Connected") + self.setupDNSJizz() } } } diff --git a/include/lokinet-dnsproxy.hpp b/include/lokinet-dnsproxy.hpp new file mode 100644 index 000000000..8f0545090 --- /dev/null +++ b/include/lokinet-dnsproxy.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +struct DNSImpl; + +@interface DNSProvider : NEDNSProxyProvider +{ + struct DNSImpl* m_Impl; +} +- (void)startProxyWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError* error))completionHandler; + +- (void)stopProxyWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler; + +- (BOOL)handleNewFlow:(NEAppProxyFlow*)flow; + +@end diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index a07c8b70d..ca7e25867 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -1,14 +1,12 @@ include(Version) -add_library(lokinet-util - STATIC +set(lokinet_util_src ${CMAKE_CURRENT_BINARY_DIR}/constants/version.cpp util/bencode.cpp util/buffer.cpp util/fs.cpp util/json.cpp util/logging/android_logger.cpp - util/logging/apple_logger.mm util/logging/buffer.cpp util/logging/file_logger.cpp util/logging/json_logger.cpp @@ -24,8 +22,18 @@ add_library(lokinet-util util/str.cpp util/thread/queue_manager.cpp util/thread/threading.cpp - util/time.cpp -) + util/time.cpp) + +if(APPLE) + list(APPEND lokinet_util_src + util/logging/apple_logger.mm) +endif() + + +add_library(lokinet-util + STATIC + ${lokinet_util_src}) + add_dependencies(lokinet-util genversion) target_include_directories(lokinet-util PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}) @@ -274,11 +282,16 @@ if(APPLE) find_library(COREFOUNDATION CoreFoundation REQUIRED) add_executable(lokinet-extension MACOSX_BUNDLE framework.mm) + add_executable(lokinet-dnsproxy MACOSX_BUNDLE dnsproxy.mm) target_link_libraries(lokinet-extension PUBLIC liblokinet ${COREFOUNDATION} ${NETEXT}) - + target_link_libraries(lokinet-dnsproxy PUBLIC + liblokinet + ${COREFOUNDATION} + ${NETEXT}) + set_target_properties(lokinet-extension PROPERTIES BUNDLE TRUE BUNDLE_EXTENSION appex @@ -289,7 +302,7 @@ if(APPLE) # Not sure what -fapplication-extension does, but XCode puts it in so... # -e _NSExtensionMain because it has that instead of a `main` function entry point, of course. target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain) - target_compile_options(lokinet-extension PRIVATE -fapplication-extension) + target_compile_options(lokinet-extension PRIVATE -fapplication-extension -fobjc-arc) add_custom_command(TARGET lokinet-extension POST_BUILD @@ -297,6 +310,21 @@ if(APPLE) $/Contents/embedded.provisionprofile ) + set_target_properties(lokinet-dnsproxy PROPERTIES + BUNDLE TRUE + BUNDLE_EXTENSION appex + MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetDNSProxy.Info.plist.in + XCODE_PRODUCT_TYPE com.apple.product-type.app-extension + ) + + target_link_options(lokinet-dnsproxy PRIVATE -fapplication-extension -e _NSExtensionMain) + target_compile_options(lokinet-dnsproxy PRIVATE -fapplication-extension -fobjc-arc) + + add_custom_command(TARGET lokinet-dnsproxy + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-dnsproxy.provisionprofile + $/Contents/embedded.provisionprofile + ) endif() diff --git a/llarp/apple.hpp b/llarp/apple.hpp new file mode 100644 index 000000000..dc35a9d95 --- /dev/null +++ b/llarp/apple.hpp @@ -0,0 +1,40 @@ +#pragma once +#ifdef __APPLE__ +#include +#include +#include + +static std::string_view +DataAsStringView(NSData* data) +{ + return std::string_view{reinterpret_cast(data.bytes), data.length}; +} + +static NSData* +StringViewToData(std::string_view data) +{ + const char* ptr = data.data(); + const size_t sz = data.size(); + return [NSData dataWithBytes:ptr length:sz]; +} + +static NSString* +StringToNSString(std::string data) +{ + NSData* ptr = StringViewToData(std::string_view{data}); + return [[NSString alloc] initWithData:ptr encoding:NSUTF8StringEncoding]; +} + +static std::string +NSStringToString(NSString* str) +{ + return std::string{[str UTF8String]}; +} + +static std::string +NSObjectToString(NSObject* obj) +{ + return NSStringToString([NSString stringWithFormat:@"%@", obj]); +} + +#endif diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 3542e9326..c10893dc8 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -1453,7 +1453,6 @@ namespace llarp auto config = std::make_shared(fs::path{}); config->Load(); config->logging.m_logLevel = eLogInfo; - config->api.m_enableRPCServer = false; config->network.m_saveProfiles = false; config->bootstrap.files.clear(); return config; diff --git a/llarp/dns/message.cpp b/llarp/dns/message.cpp index 99ffed763..f10e9b9c6 100644 --- a/llarp/dns/message.cpp +++ b/llarp/dns/message.cpp @@ -48,6 +48,12 @@ namespace llarp return true; } + util::StatusObject + MessageHeader::ToJSON() const + { + return util::StatusObject{}; + } + Message::Message(Message&& other) : hdr_id(std::move(other.hdr_id)) , hdr_fields(std::move(other.hdr_fields)) @@ -74,6 +80,11 @@ namespace llarp additional.resize(size_t(hdr.ar_count)); } + Message::Message(const Question& question) : hdr_id{0}, hdr_fields{} + { + questions.emplace_back(question); + } + bool Message::Encode(llarp_buffer_t* buf) const { @@ -122,6 +133,22 @@ namespace llarp return true; } + util::StatusObject + Message::ToJSON() const + { + std::vector ques; + std::vector ans; + for (const auto& q : questions) + { + ques.push_back(q.ToJSON()); + } + for (const auto& a : answers) + { + ans.push_back(a.ToJSON()); + } + return util::StatusObject{{"questions", ques}, {"answers", ans}}; + } + OwnedBuffer Message::ToBuffer() const { diff --git a/llarp/dns/message.hpp b/llarp/dns/message.hpp index b7d4571b1..937c37d97 100644 --- a/llarp/dns/message.hpp +++ b/llarp/dns/message.hpp @@ -33,6 +33,9 @@ namespace llarp bool Decode(llarp_buffer_t* buf) override; + util::StatusObject + ToJSON() const override; + bool operator==(const MessageHeader& other) const { @@ -44,11 +47,15 @@ namespace llarp struct Message : public Serialize { - Message(const MessageHeader& hdr); + explicit Message(const MessageHeader& hdr); + explicit Message(const Question& question); Message(Message&& other); Message(const Message& other); + util::StatusObject + ToJSON() const override; + void AddNXReply(RR_TTL_t ttl = 1); diff --git a/llarp/dns/question.cpp b/llarp/dns/question.cpp index 7ec066c30..a8c60c260 100644 --- a/llarp/dns/question.cpp +++ b/llarp/dns/question.cpp @@ -3,6 +3,7 @@ #include #include #include +#include "dns.hpp" namespace llarp { @@ -17,6 +18,13 @@ namespace llarp : qname(other.qname), qtype(other.qtype), qclass(other.qclass) {} + Question::Question(std::string name, QType_t type) + : qname{std::move(name)}, qtype{type}, qclass{qClassIN} + { + if (qname.empty()) + throw std::invalid_argument{"qname cannot be empty"}; + } + bool Question::Encode(llarp_buffer_t* buf) const { @@ -48,6 +56,12 @@ namespace llarp return true; } + util::StatusObject + Question::ToJSON() const + { + return util::StatusObject{{"qname", qname}, {"qtype", qtype}, {"qclass", qclass}}; + } + bool Question::IsName(const std::string& other) const { diff --git a/llarp/dns/question.hpp b/llarp/dns/question.hpp index f2fc00076..5434bbcdd 100644 --- a/llarp/dns/question.hpp +++ b/llarp/dns/question.hpp @@ -14,6 +14,9 @@ namespace llarp struct Question : public Serialize { Question() = default; + + explicit Question(std::string name, QType_t type); + Question(Question&& other); Question(const Question& other); bool @@ -58,6 +61,9 @@ namespace llarp /// determine if we are using this TLD bool HasTLD(const std::string& tld) const; + + util::StatusObject + ToJSON() const override; }; inline std::ostream& diff --git a/llarp/dns/rr.cpp b/llarp/dns/rr.cpp index 3fac87e9b..82ed20470 100644 --- a/llarp/dns/rr.cpp +++ b/llarp/dns/rr.cpp @@ -24,6 +24,14 @@ namespace llarp , rData(std::move(other.rData)) {} + ResourceRecord::ResourceRecord(Name_t name, RRType_t type, RR_RData_t data) + : rr_name{std::move(name)} + , rr_type{type} + , rr_class{qClassIN} + , ttl{1} + , rData{std::move(data)} + {} + bool ResourceRecord::Encode(llarp_buffer_t* buf) const { @@ -77,6 +85,17 @@ namespace llarp return true; } + util::StatusObject + ResourceRecord::ToJSON() const + { + return util::StatusObject{ + {"name", rr_name}, + {"type", rr_type}, + {"class", rr_class}, + {"ttl", ttl}, + {"rdata", std::string{reinterpret_cast(rData.data()), rData.size()}}}; + } + std::ostream& ResourceRecord::print(std::ostream& stream, int level, int spaces) const { diff --git a/llarp/dns/rr.hpp b/llarp/dns/rr.hpp index 0b50235da..e9fa72c27 100644 --- a/llarp/dns/rr.hpp +++ b/llarp/dns/rr.hpp @@ -22,12 +22,17 @@ namespace llarp ResourceRecord(const ResourceRecord& other); ResourceRecord(ResourceRecord&& other); + explicit ResourceRecord(Name_t name, RRType_t type, RR_RData_t rdata); + bool Encode(llarp_buffer_t* buf) const override; bool Decode(llarp_buffer_t* buf) override; + util::StatusObject + ToJSON() const override; + std::ostream& print(std::ostream& stream, int level, int spaces) const; diff --git a/llarp/dns/serialize.hpp b/llarp/dns/serialize.hpp index 8834de04c..94388362a 100644 --- a/llarp/dns/serialize.hpp +++ b/llarp/dns/serialize.hpp @@ -1,7 +1,7 @@ #pragma once #include - +#include #include namespace llarp @@ -20,6 +20,10 @@ namespace llarp /// decode entity from buffer virtual bool Decode(llarp_buffer_t* buf) = 0; + + /// convert this whatever into json + virtual util::StatusObject + ToJSON() const = 0; }; bool diff --git a/llarp/dnsproxy.mm b/llarp/dnsproxy.mm new file mode 100644 index 000000000..56663118c --- /dev/null +++ b/llarp/dnsproxy.mm @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +struct DNSImpl +{ + oxenmq::OxenMQ m_MQ; + std::optional m_Conn; + + explicit DNSImpl(oxenmq::address rpc) + { + m_MQ.start(); + m_MQ.connect_remote( + rpc, [this](auto conn) { m_Conn = conn; }, nullptr); + } + + bool + ShouldHookFlow(NEAppProxyFlow* flow) const + { + LogInfo(NSObjectToString(flow)); + return true; + } + + void + RelayDNSData(NEAppProxyUDPFlow* flow, NWEndpoint* remote, NSData* data) + { + if (not m_Conn) + return; + auto view = DataAsStringView(data); + + llarp_buffer_t buf{view}; + llarp::dns::MessageHeader hdr{}; + if (not hdr.Decode(&buf)) + return; + llarp::dns::Message msg{hdr}; + if (not msg.Decode(&buf)) + return; + llarp::util::StatusObject request{ + {"qname", msg.questions[0].qname}, {"qtype", msg.questions[0].qtype}}; + m_MQ.request( + *m_Conn, + "llarp.dns_query", + [flow, remote, msg = std::make_shared(std::move(msg))]( + bool good, std::vector parts) { + auto closeHandler = [flow](NSError* err) { + [flow closeWriteWithError:err]; + [flow closeReadWithError:err]; + }; + if (good and parts.size() == 1) + { + try + { + const auto obj = nlohmann::json::parse(parts[0]); + const auto result = obj["result"]; + if (const auto itr = result.find("answers"); itr != result.end()) + { + for (const auto& result : (*itr)) + { + llarp::dns::RR_RData_t rdata; + if (const auto data_itr = result.find("rdata"); data_itr != result.end()) + { + const auto data = data_itr->get(); + rdata.resize(data.size()); + std::copy_n(data.begin(), data.size(), rdata.begin()); + } + else + continue; + + msg->answers.emplace_back( + result["name"].get(), + result["type"].get(), + rdata); + } + } + } + catch (std::exception& ex) + { + LogError("dns query failed: ", ex.what()); + return; + } + const auto buf = msg->ToBuffer(); + NSData* data = StringViewToData( + std::string_view{reinterpret_cast(buf.buf.get()), buf.sz}); + [flow writeDatagrams:@[data] sentByEndpoints:@[remote] completionHandler:closeHandler]; + } + else + closeHandler(nullptr); + }, + request.dump()); + } + + void + HandleUDPFlow(NEAppProxyUDPFlow* flow) + { + auto handler = + [this, flow]( + NSArray* datagrams, NSArray* remoteEndpoints, NSError* error) { + if (error) + return; + NSInteger num = [datagrams count]; + for (NSInteger idx = 0; idx < num; ++idx) + { + RelayDNSData(flow, [remoteEndpoints objectAtIndex:idx], [datagrams objectAtIndex:idx]); + } + }; + [flow readDatagramsWithCompletionHandler:handler]; + } +}; + +@implementation DNSProvider + +- (void)startProxyWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError* error))completionHandler +{ + m_Impl = new DNSImpl{oxenmq::address{"tcp://127.0.0.1:1190"}}; + completionHandler(nil); +} + +- (void)stopProxyWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler +{ + if (m_Impl) + { + delete m_Impl; + m_Impl = nullptr; + } + completionHandler(); +} + +- (BOOL)handleNewFlow:(NEAppProxyFlow*)flow +{ + if (not [flow isKindOfClass:[NEAppProxyUDPFlow class]]) + return NO; + if (m_Impl->ShouldHookFlow(flow)) + { + NEAppProxyUDPFlow* udp = (NEAppProxyUDPFlow*)flow; + auto handler = [impl = m_Impl, udp](NSError* err) { + if (err) + return; + impl->HandleUDPFlow(udp); + }; + [flow openWithLocalEndpoint:nil completionHandler:handler]; + return YES; + } + return NO; +} + +@end diff --git a/llarp/ev/ev_libuv.cpp b/llarp/ev/ev_libuv.cpp index f9ce3c4b4..8f38750c1 100644 --- a/llarp/ev/ev_libuv.cpp +++ b/llarp/ev/ev_libuv.cpp @@ -244,7 +244,7 @@ namespace llarp::uv std::shared_ptr netif, std::function handler) { -#ifndef _WIN32 +#ifdef __linux__ using event_t = uvw::PollEvent; auto handle = m_Impl->resource(netif->PollFD()); #else @@ -264,7 +264,7 @@ namespace llarp::uv } }); -#ifndef _WIN32 +#ifdef __linux__ handle->start(uvw::PollHandle::Event::READABLE); #else handle->start(); diff --git a/llarp/framework.mm b/llarp/framework.mm index 32cde8978..f0e2b1521 100644 --- a/llarp/framework.mm +++ b/llarp/framework.mm @@ -5,8 +5,13 @@ #include #include #include +#include +#include +#include +#include -#include +const llarp::SockAddr DefaultDNSBind{"127.0.0.1:1153"}; +const llarp::SockAddr DefaultUpstreamDNS{"9.9.9.9:53"}; namespace llarp::apple { @@ -21,7 +26,7 @@ namespace llarp::apple makeVPNPlatform() override; void - Start(); + Start(std::string_view bootstrap); private: NEPacketTunnelProvider* const m_Tunnel; @@ -42,20 +47,39 @@ namespace llarp::apple llarp::net::IPPacket pkt; const llarp_buffer_t buf{static_cast(data.bytes), data.length}; if (pkt.Load(buf)) + { m_ReadQueue.tryPushBack(std::move(pkt)); + } + else + { + LogError("invalid IP packet: ", llarp::buffer_printer(DataAsStringView(data))); + } } public: - explicit VPNInterface(NEPacketTunnelProvider* tunnel) + explicit VPNInterface(NEPacketTunnelProvider* tunnel, llarp::Context* context) : m_Tunnel{tunnel}, m_ReadQueue{PacketQueueSize} { - auto handler = [this](NSArray* packets, NSArray*) { - NSUInteger num = [packets count]; - for (NSUInteger idx = 0; idx < num; ++idx) - { - NSData* pkt = [packets objectAtIndex:idx]; - OfferReadPacket(pkt); - } + context->loop->call_soon([this]() { Read(); }); + } + + void + HandleReadEvent(NSArray* packets, NSArray* protos) + { + NSUInteger num = [packets count]; + for (NSUInteger idx = 0; idx < num; ++idx) + { + NSData* pkt = [packets objectAtIndex:idx]; + OfferReadPacket(pkt); + } + Read(); + } + + void + Read() + { + auto handler = [this](NSArray* packets, NSArray* protos) { + HandleReadEvent(packets, protos); }; [m_Tunnel.packetFlow readPacketsWithCompletionHandler:handler]; } @@ -84,27 +108,27 @@ namespace llarp::apple bool WritePacket(net::IPPacket pkt) override { - const sa_family_t fam = pkt.IsV6() ? AF_INET6 : AF_INET; - const uint8_t* pktbuf = pkt.buf; + NSNumber* fam = [NSNumber numberWithInteger:(pkt.IsV6() ? AF_INET6 : AF_INET)]; + void* pktbuf = pkt.buf; const size_t pktsz = pkt.sz; - NSData* datapkt = [NSData dataWithBytes:pktbuf length:pktsz]; - NEPacket* npkt = [[NEPacket alloc] initWithData:datapkt protocolFamily:fam]; - NSArray* pkts = @[npkt]; - return [m_Tunnel.packetFlow writePacketObjects:pkts]; + NSData* datapkt = [NSData dataWithBytesNoCopy:pktbuf length:pktsz]; + return [m_Tunnel.packetFlow writePackets:@[datapkt] withProtocols:@[fam]]; } }; class VPNPlatform final : public vpn::Platform { NEPacketTunnelProvider* const m_Tunnel; + Context* const m_Context; public: - explicit VPNPlatform(NEPacketTunnelProvider* tunnel) : m_Tunnel{tunnel} + explicit VPNPlatform(NEPacketTunnelProvider* tunnel, Context* context) + : m_Tunnel{tunnel}, m_Context{context} {} std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override { - return std::make_shared(m_Tunnel); + return std::make_shared(m_Tunnel, m_Context); } }; @@ -113,16 +137,20 @@ namespace llarp::apple {} void - FrameworkContext::Start() + FrameworkContext::Start(std::string_view bootstrap) { std::promise result; - m_Runner = std::make_unique([&result, this]() { + m_Runner = std::make_unique([&result, bootstrap = std::string{bootstrap}, this]() { const RuntimeOptions opts{}; try { + auto config = llarp::Config::NetworkExtensionConfig(); + config->bootstrap.files.emplace_back(bootstrap); + config->dns.m_bind = DefaultDNSBind; + config->dns.m_upstreamDNS.push_back(DefaultUpstreamDNS); + Configure(std::move(config)); Setup(opts); - Configure(llarp::Config::NetworkExtensionConfig()); } catch (std::exception&) { @@ -140,7 +168,7 @@ namespace llarp::apple std::shared_ptr FrameworkContext::makeVPNPlatform() { - return std::make_shared(m_Tunnel); + return std::make_shared(m_Tunnel, this); } } @@ -154,9 +182,10 @@ struct ContextWrapper {} void - Start() + Start(std::string_view bootstrap) { - m_Context->Start(); + llarp::LogContext::Instance().logStream.reset(new llarp::NSLogStream{}); + m_Context->Start(std::move(bootstrap)); } void @@ -167,35 +196,42 @@ struct ContextWrapper } }; -static std::string_view -DataAsStringView(NSData* data) -{ - return std::string_view{reinterpret_cast(data.bytes), data.length}; -} - -static NSData* -StringViewToData(std::string_view data) -{ - const char* ptr = data.data(); - const size_t sz = data.size(); - return [NSData dataWithBytes:ptr length:sz]; -} - @implementation LLARPPacketTunnel - (void)startTunnelWithOptions:(NSDictionary*)options completionHandler:(void (^)(NSError*))completionHandler { - NSLog(@"OMG startTunnelWithOptions"); + llarp::huint32_t addr_{}; + llarp::huint32_t mask_{}; + if (auto maybe = llarp::FindFreeRange()) + { + addr_ = llarp::net::TruncateV6(maybe->addr); + mask_ = llarp::net::TruncateV6(maybe->netmask_bits); + } + NSString* addr = StringToNSString(addr_.ToString()); + NSString* mask = StringToNSString(mask_.ToString()); + + NSBundle* main = [NSBundle mainBundle]; + NSString* res = [main pathForResource:@"bootstrap" ofType:@"signed"]; + NSData* path = [res dataUsingEncoding:NSUTF8StringEncoding]; + m_Context = new ContextWrapper{self}; - m_Context->Start(); - [self setTunnelNetworkSettings:nullptr completionHandler:completionHandler]; + m_Context->Start(DataAsStringView(path)); + + NEPacketTunnelNetworkSettings* settings = + [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"]; + NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[addr]]; + NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[addr] + subnetMasks:@[@"255.255.255.255"]]; + ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:addr subnetMask:mask]]; + settings.IPv4Settings = ipv4; + settings.DNSSettings = dns; + [self setTunnelNetworkSettings:settings completionHandler:completionHandler]; } - (void)stopTunnelWithReason:(NEProviderStopReason)reason completionHandler:(void (^)(void))completionHandler { - NSLog(@"STOP TUNNEL"); if (m_Context) { m_Context->Stop(); @@ -209,9 +245,6 @@ StringViewToData(std::string_view data) completionHandler:(void (^)(NSData* responseData))completionHandler { const auto data = DataAsStringView(messageData); - LogInfo("app message: ", data); - completionHandler(StringViewToData("ok")); } - @end diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 81a02fad3..8da523b22 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -74,7 +74,7 @@ namespace llarp }); m_PacketRouter = std::make_unique( [this](net::IPPacket pkt) { HandleGotUserPacket(std::move(pkt)); }); -#ifdef ANDROID +#if defined(ANDROID) || defined(__APPLE__) m_Resolver = std::make_shared(r, this); m_PacketRouter->AddUDPHandler(huint16_t{53}, [&](net::IPPacket pkt) { const size_t ip_header_size = (pkt.Header()->ihl * 4); diff --git a/llarp/rpc/rpc_server.cpp b/llarp/rpc/rpc_server.cpp index 38045d6c4..8e880a187 100644 --- a/llarp/rpc/rpc_server.cpp +++ b/llarp/rpc/rpc_server.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace llarp::rpc { @@ -561,6 +562,47 @@ namespace llarp::rpc }); }); }) + .add_request_command( + "dns_query", + [&](oxenmq::Message& msg) { + HandleJSONRequest(msg, [r = m_Router](nlohmann::json obj, ReplyFunction_t reply) { + std::string endpoint{"default"}; + if (const auto itr = obj.find("endpoint"); itr != obj.end()) + { + endpoint = itr->get(); + } + std::string qname{}; + dns::QType_t qtype = dns::qTypeA; + if (const auto itr = obj.find("qname"); itr != obj.end()) + { + qname = itr->get(); + } + + if (const auto itr = obj.find("qtype"); itr != obj.end()) + { + qtype = itr->get(); + } + + dns::Message msg{dns::Question{qname, qtype}}; + + if (auto ep_ptr = (GetEndpointByName(r, endpoint))) + { + if (auto ep = reinterpret_cast(ep_ptr.get())) + { + if (ep->ShouldHookDNSMessage(msg)) + { + ep->HandleHookedDNSMessage(std::move(msg), [reply](dns::Message msg) { + reply(CreateJSONResponse(msg.ToJSON())); + }); + return; + } + } + reply(CreateJSONError("dns query not accepted by endpoint")); + return; + } + reply(CreateJSONError("no such endpoint for dns query")); + }); + }) .add_request_command("config", [&](oxenmq::Message& msg) { HandleJSONRequest(msg, [r = m_Router](nlohmann::json obj, ReplyFunction_t reply) { { From d24221e67a4c90e99cfd2cd3506e016e5987b39c Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Aug 2021 08:58:36 -0400 Subject: [PATCH 08/45] make ci run ./contrib/mac.sh with no codesigning --- .drone.jsonnet | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index 89cfddacb..af266144b 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -197,12 +197,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 - 'mkdir build', - 'cd build', - 'cmake .. -DCMAKE_CXX_FLAGS=-fcolor-diagnostics -DCMAKE_BUILD_TYPE='+build_type+' ' + - (if werror then '-DWARNINGS_AS_ERRORS=ON ' else '') + cmake_extra, - 'VERBOSE=1 make -j' + jobs, - './test/testAll --use-colour yes', + './contrib/mac.sh' ] + extra_cmds, } ] From 1272a4fbe1d9a77eed354ec8bc36dec4371362a8 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Aug 2021 09:07:31 -0400 Subject: [PATCH 09/45] add dummy sign target for ci when we don't have signing keys remove static macos from ci pipeline --- .drone.jsonnet | 5 ----- contrib/mac.sh | 2 +- daemon/CMakeLists.txt | 4 ++++ 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.drone.jsonnet b/.drone.jsonnet index af266144b..e33d98612 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -275,9 +275,4 @@ local mac_builder(name, // Macos builds: mac_builder('macOS (Release)'), mac_builder('macOS (Debug)', build_type='Debug'), - mac_builder('macOS (Static)', cmake_extra='-DBUILD_STATIC_DEPS=ON -DBUILD_SHARED_LIBS=OFF -DSTATIC_LINK=ON -DDOWNLOAD_SODIUM=FORCE -DDOWNLOAD_CURL=FORCE -DDOWNLOAD_UV=FORCE', - extra_cmds=[ - '../contrib/ci/drone-check-static-libs.sh', - '../contrib/ci/drone-static-upload.sh' - ]), ] diff --git a/contrib/mac.sh b/contrib/mac.sh index 38070ba96..548c9f8b2 100755 --- a/contrib/mac.sh +++ b/contrib/mac.sh @@ -35,5 +35,5 @@ cmake \ ninja sign echo -e "Build complete, your app is here:\n" -ls -lad daemon/lokinet.app +ls -lad $(pwd)/daemon/lokinet.app echo "" diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index ac0598f74..dae44608f 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -117,6 +117,10 @@ if(APPLE) ) 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 lokinet-dnsproxy + COMMAND "true") endif() endif() From deb0a982be653d60da31587bb137c1228a3fbfac Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 16 Aug 2021 10:55:53 -0400 Subject: [PATCH 10/45] it works --- daemon/lokinet.swift | 5 +++- llarp/config/config.cpp | 4 +-- llarp/config/config.hpp | 2 +- llarp/context.cpp | 4 +-- llarp/framework.mm | 62 ++++++++++++++++++++++++----------------- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift index a12c1da79..9ebf76940 100644 --- a/daemon/lokinet.swift +++ b/daemon/lokinet.swift @@ -22,6 +22,9 @@ class LokinetMain: NSObject, NSApplicationDelegate { NSLog("setting up dns settings") let dns = NEDNSSettingsManager.shared() let settings = NEDNSSettings(servers: ["172.16.0.1"]) + settings.matchDomains = ["*.loki", "*.snode"] + settings.matchDomainsNoSearch = true + settings.domainName = "localhost.loki" dns.dnsSettings = settings dns.loadFromPreferences { [self] (error: Error?) -> Void in if let error = error { @@ -94,6 +97,7 @@ class LokinetMain: NSObject, NSApplicationDelegate { providerProtocol.serverAddress = "loki.loki" // Needs to be set to some non-null dummy value providerProtocol.username = "anonymous" providerProtocol.providerBundleIdentifier = self.lokinetComponent + 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. providerProtocol.includeAllNetworks = false @@ -155,7 +159,6 @@ class LokinetMain: NSObject, NSApplicationDelegate { NSLog("VPN is disconnecting...") } else if self.vpnManager.connection.status == .connected { NSLog("VPN Connected") - self.setupDNSJizz() } } } diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index c10893dc8..caae01abf 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -1448,13 +1448,13 @@ namespace llarp #ifdef __APPLE__ std::shared_ptr - Config::NetworkExtensionConfig() + Config::NetworkExtensionConfig(std::string exit) { auto config = std::make_shared(fs::path{}); config->Load(); config->logging.m_logLevel = eLogInfo; - config->network.m_saveProfiles = false; config->bootstrap.files.clear(); + config->network.m_LNSExitMap.Insert(IPRange{}, exit); return config; } #endif diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 35360aeb8..994725e02 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -262,7 +262,7 @@ namespace llarp #ifdef __APPLE__ static std::shared_ptr - NetworkExtensionConfig(); + NetworkExtensionConfig(std::string exit); #endif private: diff --git a/llarp/context.cpp b/llarp/context.cpp index 9bf260ce7..59a54dc28 100644 --- a/llarp/context.cpp +++ b/llarp/context.cpp @@ -138,8 +138,8 @@ namespace llarp if (IsStopping()) return; - if (CallSafe(std::bind(&Context::HandleSignal, this, SIGTERM))) - closeWaiter = std::make_unique>(); + loop->call([this]() { HandleSignal(SIGTERM); }); + closeWaiter = std::make_unique>(); } bool diff --git a/llarp/framework.mm b/llarp/framework.mm index f0e2b1521..af427a532 100644 --- a/llarp/framework.mm +++ b/llarp/framework.mm @@ -26,7 +26,7 @@ namespace llarp::apple makeVPNPlatform() override; void - Start(std::string_view bootstrap); + Start(std::string_view bootstrap, std::string exit); private: NEPacketTunnelProvider* const m_Tunnel; @@ -137,29 +137,30 @@ namespace llarp::apple {} void - FrameworkContext::Start(std::string_view bootstrap) + FrameworkContext::Start(std::string_view bootstrap, std::string exit) { std::promise result; - m_Runner = std::make_unique([&result, bootstrap = std::string{bootstrap}, this]() { - const RuntimeOptions opts{}; - try - { - auto config = llarp::Config::NetworkExtensionConfig(); - config->bootstrap.files.emplace_back(bootstrap); - config->dns.m_bind = DefaultDNSBind; - config->dns.m_upstreamDNS.push_back(DefaultUpstreamDNS); - Configure(std::move(config)); - Setup(opts); - } - catch (std::exception&) - { - result.set_exception(std::current_exception()); - return; - } - result.set_value(); - Run(opts); - }); + m_Runner = + std::make_unique([&result, bootstrap = std::string{bootstrap}, exit, this]() { + const RuntimeOptions opts{}; + try + { + auto config = llarp::Config::NetworkExtensionConfig(exit); + config->bootstrap.files.emplace_back(bootstrap); + config->dns.m_bind = DefaultDNSBind; + config->dns.m_upstreamDNS.push_back(DefaultUpstreamDNS); + Configure(std::move(config)); + Setup(opts); + } + catch (std::exception&) + { + result.set_exception(std::current_exception()); + return; + } + result.set_value(); + Run(opts); + }); auto ftr = result.get_future(); ftr.get(); @@ -182,10 +183,10 @@ struct ContextWrapper {} void - Start(std::string_view bootstrap) + Start(std::string_view bootstrap, std::string exit) { llarp::LogContext::Instance().logStream.reset(new llarp::NSLogStream{}); - m_Context->Start(std::move(bootstrap)); + m_Context->Start(std::move(bootstrap), std::move(exit)); } void @@ -210,20 +211,29 @@ struct ContextWrapper } NSString* addr = StringToNSString(addr_.ToString()); NSString* mask = StringToNSString(mask_.ToString()); + llarp::huint32_t dnsaddr_{addr_ & mask_}; + NSString* dnsaddr = StringToNSString(dnsaddr_.ToString()); + NSLog(@"%@", dnsaddr); NSBundle* main = [NSBundle mainBundle]; NSString* res = [main pathForResource:@"bootstrap" ofType:@"signed"]; NSData* path = [res dataUsingEncoding:NSUTF8StringEncoding]; m_Context = new ContextWrapper{self}; - m_Context->Start(DataAsStringView(path)); + m_Context->Start(DataAsStringView(path), "exit.loki"); NEPacketTunnelNetworkSettings* settings = [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"]; - NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[addr]]; + NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[dnsaddr]]; + dns.domainName = @"localhost.loki"; + dns.matchDomains = @[@"*.snode", @"*.loki"]; + dns.matchDomainsNoSearch = true; + dns.searchDomains = @[]; + // dns.dnsProtocol = NEDNSProtocolCleartext; NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[addr] subnetMasks:@[@"255.255.255.255"]]; - ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:addr subnetMask:mask]]; + ipv4.includedRoutes = @[[NEIPv4Route defaultRoute]]; + // ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:addr subnetMask:mask]]; settings.IPv4Settings = ipv4; settings.DNSSettings = dns; [self setTunnelNetworkSettings:settings completionHandler:completionHandler]; From 3f0b34e860b3654ee479f44291836bf45434f0ac Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Mon, 23 Aug 2021 12:48:55 -0300 Subject: [PATCH 11/45] Consolidate apple-specific bits into llarp/apple --- llarp/CMakeLists.txt | 66 +------------------ llarp/apple/CMakeLists.txt | 61 +++++++++++++++++ .../{util/logging => apple}/apple_logger.hpp | 6 +- llarp/{util/logging => apple}/apple_logger.mm | 4 +- llarp/{ => apple}/dnsproxy.mm | 0 llarp/{ => apple}/framework.mm | 2 +- 6 files changed, 67 insertions(+), 72 deletions(-) create mode 100644 llarp/apple/CMakeLists.txt rename llarp/{util/logging => apple}/apple_logger.hpp (91%) rename llarp/{util/logging => apple}/apple_logger.mm (93%) rename llarp/{ => apple}/dnsproxy.mm (100%) rename llarp/{ => apple}/framework.mm (99%) diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index ca7e25867..30e90b7be 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -1,6 +1,6 @@ include(Version) -set(lokinet_util_src +add_library(lokinet-util ${CMAKE_CURRENT_BINARY_DIR}/constants/version.cpp util/bencode.cpp util/buffer.cpp @@ -24,15 +24,6 @@ set(lokinet_util_src util/thread/threading.cpp util/time.cpp) -if(APPLE) - list(APPEND lokinet_util_src - util/logging/apple_logger.mm) -endif() - - -add_library(lokinet-util - STATIC - ${lokinet_util_src}) add_dependencies(lokinet-util genversion) @@ -46,11 +37,6 @@ target_link_libraries(lokinet-util PUBLIC oxenmq::oxenmq ) -if(APPLE) - find_library(FOUNDATION Foundation REQUIRED) - target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) -endif() - if(ANDROID) target_link_libraries(lokinet-util PUBLIC log) endif() @@ -277,55 +263,7 @@ if(BUILD_LIBLOKINET) endif() if(APPLE) - # god made apple so that man may suffer - find_library(NETEXT NetworkExtension REQUIRED) - find_library(COREFOUNDATION CoreFoundation REQUIRED) - - add_executable(lokinet-extension MACOSX_BUNDLE framework.mm) - add_executable(lokinet-dnsproxy MACOSX_BUNDLE dnsproxy.mm) - target_link_libraries(lokinet-extension PUBLIC - liblokinet - ${COREFOUNDATION} - ${NETEXT}) - target_link_libraries(lokinet-dnsproxy PUBLIC - liblokinet - ${COREFOUNDATION} - ${NETEXT}) - - 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 - ) - - # Not sure what -fapplication-extension does, but XCode puts it in so... - # -e _NSExtensionMain because it has that instead of a `main` function entry point, of course. - target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain) - target_compile_options(lokinet-extension PRIVATE -fapplication-extension -fobjc-arc) - - add_custom_command(TARGET lokinet-extension - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.provisionprofile - $/Contents/embedded.provisionprofile - ) - - set_target_properties(lokinet-dnsproxy PROPERTIES - BUNDLE TRUE - BUNDLE_EXTENSION appex - MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetDNSProxy.Info.plist.in - XCODE_PRODUCT_TYPE com.apple.product-type.app-extension - ) - - target_link_options(lokinet-dnsproxy PRIVATE -fapplication-extension -e _NSExtensionMain) - target_compile_options(lokinet-dnsproxy PRIVATE -fapplication-extension -fobjc-arc) - - add_custom_command(TARGET lokinet-dnsproxy - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-dnsproxy.provisionprofile - $/Contents/embedded.provisionprofile - ) - + add_subdirectory(apple) endif() foreach(lokinet_lib liblokinet lokinet-platform lokinet-util lokinet-cryptography) diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt new file mode 100644 index 000000000..0fdea9a41 --- /dev/null +++ b/llarp/apple/CMakeLists.txt @@ -0,0 +1,61 @@ + +# 3.13+ so that we can add link libraries to parent targets +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?") +endif() + +# god made apple so that man may suffer + +find_library(FOUNDATION Foundation REQUIRED) +find_library(NETEXT NetworkExtension REQUIRED) +find_library(COREFOUNDATION CoreFoundation REQUIRED) + +target_sources(lokinet-util PRIVATE apple_logger.mm) +target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) + +add_executable(lokinet-extension MACOSX_BUNDLE framework.mm) +add_executable(lokinet-dnsproxy MACOSX_BUNDLE dnsproxy.mm) +target_link_libraries(lokinet-extension PUBLIC + liblokinet + ${COREFOUNDATION} + ${NETEXT}) +target_link_libraries(lokinet-dnsproxy PUBLIC + liblokinet + ${COREFOUNDATION} + ${NETEXT}) + +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 + ) + +# Not sure what -fapplication-extension does, but XCode puts it in so... +# -e _NSExtensionMain because it has that instead of a `main` function entry point, of course. +target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain) +target_compile_options(lokinet-extension PRIVATE -fapplication-extension -fobjc-arc) + +add_custom_command(TARGET lokinet-extension + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.provisionprofile + $/Contents/embedded.provisionprofile + ) + +set_target_properties(lokinet-dnsproxy PROPERTIES + BUNDLE TRUE + BUNDLE_EXTENSION appex + MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetDNSProxy.Info.plist.in + XCODE_PRODUCT_TYPE com.apple.product-type.app-extension + ) + +target_link_options(lokinet-dnsproxy PRIVATE -fapplication-extension -e _NSExtensionMain) +target_compile_options(lokinet-dnsproxy PRIVATE -fapplication-extension -fobjc-arc) + +add_custom_command(TARGET lokinet-dnsproxy + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-dnsproxy.provisionprofile + $/Contents/embedded.provisionprofile + ) diff --git a/llarp/util/logging/apple_logger.hpp b/llarp/apple/apple_logger.hpp similarity index 91% rename from llarp/util/logging/apple_logger.hpp rename to llarp/apple/apple_logger.hpp index 00450b391..1546392d1 100644 --- a/llarp/util/logging/apple_logger.hpp +++ b/llarp/apple/apple_logger.hpp @@ -1,6 +1,6 @@ #pragma once -#ifdef __APPLE__ -#include "logstream.hpp" + +#include namespace llarp { @@ -28,5 +28,3 @@ namespace llarp {} }; } // namespace llarp - -#endif diff --git a/llarp/util/logging/apple_logger.mm b/llarp/apple/apple_logger.mm similarity index 93% rename from llarp/util/logging/apple_logger.mm rename to llarp/apple/apple_logger.mm index e5ca746c1..52b544e58 100644 --- a/llarp/util/logging/apple_logger.mm +++ b/llarp/apple/apple_logger.mm @@ -1,6 +1,5 @@ -#ifdef __APPLE__ #include "apple_logger.hpp" -#include "logger_internal.hpp" +#include #include @@ -35,4 +34,3 @@ namespace llarp {} } // namespace llarp -#endif diff --git a/llarp/dnsproxy.mm b/llarp/apple/dnsproxy.mm similarity index 100% rename from llarp/dnsproxy.mm rename to llarp/apple/dnsproxy.mm diff --git a/llarp/framework.mm b/llarp/apple/framework.mm similarity index 99% rename from llarp/framework.mm rename to llarp/apple/framework.mm index af427a532..be7af8022 100644 --- a/llarp/framework.mm +++ b/llarp/apple/framework.mm @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include From 712b5a5608e1e2412519e815c716cd4b5b494a08 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 25 Aug 2021 13:30:30 -0300 Subject: [PATCH 12/45] Tweak icns generation to only run when necessary --- daemon/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index dae44608f..65fd29fe1 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -75,9 +75,11 @@ 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") - add_custom_target(icons ALL - COMMAND ${PROJECT_SOURCE_DIR}/contrib/macos/mk-icns.sh ${PROJECT_SOURCE_DIR}/contrib/lokinet.svg ${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns + 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) file(DOWNLOAD "https://seed.lokinet.org/lokinet.signed" ${CMAKE_CURRENT_BINARY_DIR}/bootstrap.signed) add_custom_command(TARGET lokinet @@ -101,7 +103,7 @@ if(APPLE) 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 "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns" + 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)") From 329da951b71bf2194c329e852c9cb06ab3f9bcab Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 25 Aug 2021 20:28:58 -0300 Subject: [PATCH 13/45] Apple OS interface cleanup & refactoring - Add a C callback interface (context_wrapper.h) between lokinet and the objective-C code so that: - we can use objective-C (rather than objective-C++), which seems more likely to be supported by Apple into the future; - we minimize the amount of code that needs to be aware of the Apple APIs. - this replaces apple logger objective c++ implementation with a plain c++ implementation that takes a very simple C callback (provided from the obj-c code) to actually make the call to NSLog. - Add various documentation to the code of what is going on. - Send all DNS traffic to the primary IP on the tun interface. The match prefixes simply don't work as advertised, and have weird shit (like even if you get it working for some domains, "instagram.com" still doesn't because of god-knows-what Apple internal politics). - Drop the dns proxy code as we don't need it anymore. - Don't use 9.9.9.9 for default DNS. (We might consider the unfiltered 9.9.9.10 as an alternative default, but if we do it should be a global lokinet change rather than a Mac-specific change). - Parse a lokinet.ini in the data directory, if it exists. (Since we are sandboxed, it is an app-specific "home" directory so is probably buried god knows where, but at least the GUI ought to be able to get it to let users add things to it). - This commit also adds a swift version of the PacketTunnelProvider glue, which ought to work in theory, but the *tooling* for cmake is so underdeveloped that I couldn't find any way to actually get the damn thing working. So I'm committing it here anyway (and will revert it away in the next commit) in case we someday want to switch to it. - --- contrib/format.sh | 2 +- contrib/macos/sign.sh.in | 3 - daemon/CMakeLists.txt | 5 +- llarp/apple/CMakeLists.txt | 41 ++--- llarp/apple/PacketTunnelProvider.m | 134 +++++++++++++++ llarp/apple/PacketTunnelProvider.swift | 129 ++++++++++++++ .../{apple_logger.mm => apple_logger.cpp} | 17 +- llarp/apple/apple_logger.hpp | 18 +- llarp/apple/context.hpp | 23 +++ llarp/apple/context_wrapper.cpp | 162 ++++++++++++++++++ llarp/apple/context_wrapper.h | 94 ++++++++++ llarp/apple/vpn_interface.cpp | 52 ++++++ llarp/apple/vpn_interface.hpp | 51 ++++++ llarp/apple/vpn_platform.hpp | 31 ++++ 14 files changed, 711 insertions(+), 51 deletions(-) create mode 100644 llarp/apple/PacketTunnelProvider.m create mode 100644 llarp/apple/PacketTunnelProvider.swift rename llarp/apple/{apple_logger.mm => apple_logger.cpp} (53%) create mode 100644 llarp/apple/context.hpp create mode 100644 llarp/apple/context_wrapper.cpp create mode 100644 llarp/apple/context_wrapper.h create mode 100644 llarp/apple/vpn_interface.cpp create mode 100644 llarp/apple/vpn_interface.hpp create mode 100644 llarp/apple/vpn_platform.hpp diff --git a/contrib/format.sh b/contrib/format.sh index 5b5f5a495..785d9ba54 100755 --- a/contrib/format.sh +++ b/contrib/format.sh @@ -18,7 +18,7 @@ fi cd "$(dirname $0)/../" if [ "$1" = "verify" ] ; then - if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|mm)$' | grep -v '\#') | grep '' | wc -l) -ne 0 ] ; then + if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|mm?)$' | grep -v '\#') | grep '' | wc -l) -ne 0 ] ; then exit 1 fi else diff --git a/contrib/macos/sign.sh.in b/contrib/macos/sign.sh.in index af3d18d55..6ebf0859a 100755 --- a/contrib/macos/sign.sh.in +++ b/contrib/macos/sign.sh.in @@ -3,9 +3,6 @@ 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" -codesign --verbose=4 --force -s "@CODESIGN_APPEX@" \ - --entitlements "@PROJECT_SOURCE_DIR@/contrib/macos/lokinet-dnsproxy.entitlements.plist" \ - --deep --strict --timestamp --options=runtime "@SIGN_TARGET@/Contents/PlugIns/lokinet-dnsproxy.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" \ diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index 65fd29fe1..febc7314a 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -88,7 +88,6 @@ if(APPLE) $/Contents/Resources/bootstrap.signed COMMAND mkdir -p $/Contents/PlugIns COMMAND cp -a $ $/Contents/PlugIns/ - COMMAND cp -a $ $/Contents/PlugIns/ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet.provisionprofile $/Contents/embedded.provisionprofile ) @@ -114,14 +113,14 @@ if(APPLE) @ONLY) add_custom_target( sign - DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension lokinet-dnsproxy + 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 lokinet-dnsproxy + DEPENDS lokinet lokinet-extension COMMAND "true") endif() endif() diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt index 0fdea9a41..8344e90a1 100644 --- a/llarp/apple/CMakeLists.txt +++ b/llarp/apple/CMakeLists.txt @@ -12,16 +12,26 @@ find_library(FOUNDATION Foundation REQUIRED) find_library(NETEXT NetworkExtension REQUIRED) find_library(COREFOUNDATION CoreFoundation REQUIRED) -target_sources(lokinet-util PRIVATE apple_logger.mm) +target_sources(lokinet-util PRIVATE apple_logger.cpp) target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) -add_executable(lokinet-extension MACOSX_BUNDLE framework.mm) -add_executable(lokinet-dnsproxy MACOSX_BUNDLE dnsproxy.mm) -target_link_libraries(lokinet-extension PUBLIC +target_sources(lokinet-platform PRIVATE vpn_interface.cpp context_wrapper.cpp) + +add_executable(lokinet-extension MACOSX_BUNDLE + PacketTunnelProvider.m + ) +target_link_libraries(lokinet-extension PRIVATE liblokinet ${COREFOUNDATION} ${NETEXT}) -target_link_libraries(lokinet-dnsproxy PUBLIC + +# 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_link_libraries(lokinet-extension PUBLIC liblokinet ${COREFOUNDATION} ${NETEXT}) @@ -33,29 +43,8 @@ set_target_properties(lokinet-extension PROPERTIES XCODE_PRODUCT_TYPE com.apple.product-type.app-extension ) -# Not sure what -fapplication-extension does, but XCode puts it in so... -# -e _NSExtensionMain because it has that instead of a `main` function entry point, of course. -target_link_options(lokinet-extension PRIVATE -fapplication-extension -e _NSExtensionMain) -target_compile_options(lokinet-extension PRIVATE -fapplication-extension -fobjc-arc) - add_custom_command(TARGET lokinet-extension POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-extension.provisionprofile $/Contents/embedded.provisionprofile ) - -set_target_properties(lokinet-dnsproxy PROPERTIES - BUNDLE TRUE - BUNDLE_EXTENSION appex - MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/contrib/macos/LokinetDNSProxy.Info.plist.in - XCODE_PRODUCT_TYPE com.apple.product-type.app-extension - ) - -target_link_options(lokinet-dnsproxy PRIVATE -fapplication-extension -e _NSExtensionMain) -target_compile_options(lokinet-dnsproxy PRIVATE -fapplication-extension -fobjc-arc) - -add_custom_command(TARGET lokinet-dnsproxy - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/contrib/macos/lokinet-dnsproxy.provisionprofile - $/Contents/embedded.provisionprofile - ) diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m new file mode 100644 index 000000000..b203095f9 --- /dev/null +++ b/llarp/apple/PacketTunnelProvider.m @@ -0,0 +1,134 @@ +#include +#include +#include "context_wrapper.h" + +NSString* error_domain = @"com.loki-project.lokinet"; + +@interface LLARPPacketTunnel : NEPacketTunnelProvider +{ + void* lokinet; +} + +- (void)startTunnelWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError* error))completionHandler; + +- (void)stopTunnelWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler; + +- (void)handleAppMessage:(NSData*)messageData + completionHandler:(void (^)(NSData* responseData))completionHandler; + +- (void)readPackets; + +@end + +void nslogger(const char* msg) { NSLog(@"%s", msg); } + +void packet_writer(int af, const void* data, size_t size, void* ctx) { + if (ctx == nil || data == nil) + return; + + 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]]; +} + +void start_packet_reader(void* ctx) { + if (ctx == nil) + return; + + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + [t readPackets]; +} + +@implementation LLARPPacketTunnel + +- (void)readPackets +{ + [self.packetFlow readPacketObjectsWithCompletionHandler: ^(NSArray* packets) { + if (lokinet == nil) + return; + for (NEPacket* p in packets) { + llarp_apple_incoming(lokinet, p.data.bytes, p.data.length); + } + [self readPackets]; + }]; +} + +- (void)startTunnelWithOptions:(NSDictionary*)options + completionHandler:(void (^)(NSError*))completionHandler +{ + char ip_buf[16]; + char mask_buf[16]; + char dns_buf[16]; + + NSString* default_bootstrap = [[NSBundle mainBundle] pathForResource:@"bootstrap" ofType:@"signed"]; + + lokinet = llarp_apple_init(nslogger, NSHomeDirectory().UTF8String, default_bootstrap.UTF8String, ip_buf, mask_buf, dns_buf); + if (!lokinet) { + NSError *init_failure = [NSError errorWithDomain:error_domain code:500 userInfo:@{@"Error": @"Failed to initialize lokinet"}]; + NSLog(@"%@", [init_failure localizedDescription]); + return completionHandler(init_failure); + } + + NSString* ip = [[NSString alloc] initWithUTF8String:ip_buf]; + NSString* mask = [[NSString alloc] initWithUTF8String:mask_buf]; + NSString* dnsaddr = [[NSString alloc] initWithUTF8String:dns_buf]; + + NEPacketTunnelNetworkSettings* settings = + [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"]; + NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[dnsaddr]]; + dns.domainName = @"localhost.loki"; + // In theory, matchDomains is supposed to be set to DNS suffixes that we resolve. This seems + // highly unreliable, though: often it just doesn't work at all (perhaps only if we make ourselves + // the default route?), and even when it does work, it seems there are secret reasons that some + // domains (such as instagram.com) still won't work because there's some magic sauce in the OS + // that Apple engineers don't want to disclose ("This is what I expected, actually. Although I + // will not comment on what I believe is happening here", from + // https://developer.apple.com/forums/thread/685410). + // + // So the documentation sucks and the feature doesn't appear to work, so as much as it would be + // nice to capture only .loki and .snode when not in exit mode, we can't, so capture everything + // and use our default upstream. + dns.matchDomains = @[@""]; + dns.matchDomainsNoSearch = true; + dns.searchDomains = @[]; + NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[ip] + subnetMasks:@[mask]]; + settings.IPv4Settings = ipv4; + settings.DNSSettings = dns; + [self setTunnelNetworkSettings:settings completionHandler:^(NSError* err) { + if (err) { + NSLog(@"Failed to configure lokinet tunnel: %@", err); + return completionHandler(err); + } + + int start_ret = llarp_apple_start(lokinet, packet_writer, start_packet_reader, (__bridge void*) self); + if (start_ret != 0) { + NSError *start_failure = [NSError errorWithDomain:error_domain code:start_ret userInfo:@{@"Error": @"Failed to start lokinet"}]; + NSLog(@"%@", start_failure); + lokinet = nil; + return completionHandler(start_failure); + } + completionHandler(nil); + }]; +} + +- (void)stopTunnelWithReason:(NEProviderStopReason)reason + completionHandler:(void (^)(void))completionHandler +{ + if (lokinet) { + llarp_apple_shutdown(lokinet); + lokinet = nil; + } + completionHandler(); +} + +- (void)handleAppMessage:(NSData*)messageData + completionHandler:(void (^)(NSData* responseData))completionHandler +{ + NSData* response = [NSData dataWithBytesNoCopy:"ok" length:3 freeWhenDone:NO]; + completionHandler(response); +} +@end diff --git a/llarp/apple/PacketTunnelProvider.swift b/llarp/apple/PacketTunnelProvider.swift new file mode 100644 index 000000000..1cee28bed --- /dev/null +++ b/llarp/apple/PacketTunnelProvider.swift @@ -0,0 +1,129 @@ +/// Lokinet network extension swift glue layer + +import NetworkExtension + +enum LokinetError: Error { + case runtimeError(String) +} + +func packet_writer(af: Int32, data: UnsafeRawPointer?, size: Int, ctx: UnsafeMutableRawPointer?) { + if ctx == nil || data == nil { + return + } + let tunnel = ctx!.assumingMemoryBound(to: PacketTunnelProvider.self).pointee + + let packet = NEPacket( + data: Data(bytes: data!, count: 1), + protocolFamily: sa_family_t(af)) + tunnel.packetFlow.writePacketObjects([packet]) +} + + +func start_packet_reader(ctx: UnsafeMutableRawPointer?) { + let tunnel = ctx?.assumingMemoryBound(to: PacketTunnelProvider.self).pointee + tunnel?.readHandler() +} + + +class PacketTunnelProvider: NEPacketTunnelProvider { + + var lokinet: UnsafeMutableRawPointer? + + func readHandler() { + packetFlow.readPacketObjects() { (packets: [NEPacket]) in + if self.lokinet == nil { + return + } + + for p in packets { + p.data.withUnsafeBytes { (buf: UnsafeRawBufferPointer) -> Void in + llarp_apple_incoming(self.lokinet, buf.baseAddress!, buf.count) + } + } + + self.readHandler() + } + } + + override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { + + var ip_buf = Array(repeating: 0, count: 16) + var mask_buf = Array(repeating: 0, count: 16) + var dns_buf = Array(repeating: 0, count: 16) + + lokinet = llarp_apple_init(NSHomeDirectory(), &ip_buf, &mask_buf, &dns_buf) + if lokinet == nil { + NSLog("Lokinet initialization failed!") + completionHandler(LokinetError.runtimeError("Lokinet initialization failed")) + return + } + + let ip = String(cString: ip_buf) + let mask = String(cString: mask_buf) + let dns_addr = String(cString: dns_buf) + + NSLog("Lokinet configured with address %s/%s, dns %s", ip, mask, dns_addr) + + let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") + settings.ipv4Settings = NEIPv4Settings(addresses: [ip], subnetMasks: [mask]) + let dns = NEDNSSettings(servers: [dns_addr]) + dns.domainName = "localhost.loki" + dns.matchDomains = ["snode", "loki"] + dns.matchDomainsNoSearch = true + dns.searchDomains = [] + settings.dnsSettings = dns + + let condition = NSCondition() + condition.lock() + defer { condition.unlock() } + + var system_error: Error? + + setTunnelNetworkSettings(settings) { error in + system_error = error + condition.signal() + } + + condition.wait() + + if let error = system_error { + NSLog("Failed to set up tunnel: %s", error.localizedDescription) + lokinet = nil + completionHandler(error) + return + } + + var myself = self + let start_ret = llarp_apple_start(lokinet, packet_writer, start_packet_reader, &myself) + if start_ret != 0 { + NSLog("Lokinet failed to start!") + lokinet = nil + completionHandler(LokinetError.runtimeError("Lokinet failed to start")) + return + } + completionHandler(nil) + } + + override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { + if lokinet != nil { + llarp_apple_shutdown(lokinet) + lokinet = nil + } + completionHandler() + } + + override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { + if let handler = completionHandler { + handler(messageData) + } + } + + override func sleep(completionHandler: @escaping () -> Void) { + // FIXME - do we need to kick lokinet here? + completionHandler() + } + + override func wake() { + // FIXME - do we need to kick lokinet here? + } +} diff --git a/llarp/apple/apple_logger.mm b/llarp/apple/apple_logger.cpp similarity index 53% rename from llarp/apple/apple_logger.mm rename to llarp/apple/apple_logger.cpp index 52b544e58..4a41c78cf 100644 --- a/llarp/apple/apple_logger.mm +++ b/llarp/apple/apple_logger.cpp @@ -1,9 +1,6 @@ #include "apple_logger.hpp" -#include -#include - -namespace llarp +namespace llarp::apple { void NSLogStream::PreLog( @@ -22,15 +19,7 @@ namespace llarp void NSLogStream::Print(LogLevel, const char*, const std::string& msg) { - const char* msg_ptr = msg.c_str(); - const char* msg_fmt = "%s"; - NSString* fmt = [[NSString alloc] initWithUTF8String:msg_ptr]; - NSString* str = [[NSString alloc] initWithUTF8String:msg_fmt]; - NSLog(fmt, str); + ns_logger(msg.c_str()); } - void - NSLogStream::PostLog(std::stringstream&) const - {} - -} // namespace llarp +} // namespace llarp::apple diff --git a/llarp/apple/apple_logger.hpp b/llarp/apple/apple_logger.hpp index 1546392d1..b97810c76 100644 --- a/llarp/apple/apple_logger.hpp +++ b/llarp/apple/apple_logger.hpp @@ -1,11 +1,17 @@ #pragma once +#include #include -namespace llarp +namespace llarp::apple { struct NSLogStream : public ILogStream { + using ns_logger_callback = void (*)(const char* log_this); + + NSLogStream(ns_logger_callback logger) : ns_logger{logger} + {} + void PreLog( std::stringstream& s, @@ -18,13 +24,17 @@ namespace llarp Print(LogLevel lvl, const char* tag, const std::string& msg) override; void - PostLog(std::stringstream& ss) const override; + PostLog(std::stringstream& ss) const override + {} - virtual void + void ImmediateFlush() override {} void Tick(llarp_time_t) override {} + + private: + ns_logger_callback ns_logger; }; -} // namespace llarp +} // namespace llarp::apple diff --git a/llarp/apple/context.hpp b/llarp/apple/context.hpp new file mode 100644 index 000000000..e25090262 --- /dev/null +++ b/llarp/apple/context.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "vpn_platform.hpp" + +namespace llarp::apple +{ + struct Context : public llarp::Context + { + std::shared_ptr + makeVPNPlatform() override + { + return std::make_shared(*this, m_PacketWriter, m_OnReadable); + } + + // Callbacks that must be set for packet handling *before* calling Setup/Configure/Run; the main + // point of these is to get passed through to VPNInterface, which will be called during setup, + // after construction. + VPNInterface::packet_write_callback m_PacketWriter; + VPNInterface::on_readable_callback m_OnReadable; + }; + +} // namespace llarp::apple diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp new file mode 100644 index 000000000..bd781fa89 --- /dev/null +++ b/llarp/apple/context_wrapper.cpp @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include +#include "vpn_interface.hpp" +#include "context_wrapper.h" +#include "context.hpp" +#include "apple_logger.hpp" + +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; + std::thread runner; + + std::weak_ptr iface; + }; + +} // namespace + +void* +llarp_apple_init( + ns_logger_callback ns_logger, + const char* config_dir_, + const char* default_bootstrap, + char* ip, + char* netmask, + char* dns) +{ + llarp::LogContext::Instance().logStream = std::make_unique(ns_logger); + + try + { + auto config_dir = fs::u8path(config_dir_); + auto config = std::make_shared(config_dir); + std::optional config_path = config_dir / "lokinet.ini"; + if (!fs::exists(*config_path)) + config_path.reset(); + config->Load(config_path); + + // If no range is specified then go look for a free one, set that in the config, and then return + // it to the caller via the char* parameters. + auto& range = config->network.m_ifaddr; + if (!range.addr.h) + { + if (auto maybe = llarp::FindFreeRange()) + range = *maybe; + else + throw std::runtime_error{"Could not find any free IP range"}; + } + auto addr = llarp::net::TruncateV6(range.addr).ToString(); + auto mask = llarp::net::TruncateV6(range.netmask_bits).ToString(); + if (addr.size() > 15 || mask.size() > 15) + throw std::runtime_error{"Unexpected non-IPv4 tunnel range configured"}; + std::strcpy(ip, addr.c_str()); + std::strcpy(netmask, mask.c_str()); + // XXX possibly DNS needs to be the .0 instead of the .1 because mac reasons? + std::strcpy(dns, addr.c_str()); + + // 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; + + // If no explicit bootstrap then set the system default one included with the app bundle + if (config->bootstrap.files.empty()) + config->bootstrap.files.push_back(fs::u8path(default_bootstrap)); + + auto inst = std::make_unique(); + inst->context.Configure(std::move(config)); + return inst.release(); + } + catch (const std::exception& e) + { + LogError("Failed to initialize lokinet from config: ", e.what()); + } + return nullptr; +} + +int +llarp_apple_start( + void* lokinet, + packet_writer_callback packet_writer, + start_reading_callback start_reading, + void* callback_context) +{ + auto* inst = static_cast(lokinet); + inst->context.m_PacketWriter = [inst, packet_writer, callback_context]( + int af_family, void* data, size_t size) { + packet_writer(af_family, data, size, callback_context); + return true; + }; + + inst->context.m_OnReadable = + [inst, start_reading, callback_context](llarp::apple::VPNInterface& iface) { + inst->iface = iface.weak_from_this(); + start_reading(callback_context); + }; + + std::promise result; + inst->runner = std::thread{[inst, &result] { + const llarp::RuntimeOptions opts{}; + try + { + inst->context.Setup(opts); + } + catch (...) + { + result.set_exception(std::current_exception()); + return; + } + result.set_value(); + inst->context.Run(opts); + }}; + + try + { + result.get_future().get(); + } + catch (const std::exception& e) + { + LogError("Failed to initialize lokinet: ", e.what()); + return -1; + } + + return 0; +} + +int +llarp_apple_incoming(void* lokinet, const void* bytes, size_t size) +{ + auto& inst = *static_cast(lokinet); + + auto iface = inst.iface.lock(); + if (!iface) + return -2; + + llarp_buffer_t buf{static_cast(bytes), size}; + if (iface->OfferReadPacket(buf)) + return 0; + + LogError("invalid IP packet: ", llarp::buffer_printer(buf)); + return -1; +} + +void +llarp_apple_shutdown(void* lokinet) +{ + auto* inst = static_cast(lokinet); + + inst->context.CloseAsync(); + inst->context.Wait(); + inst->runner.join(); + delete inst; +} diff --git a/llarp/apple/context_wrapper.h b/llarp/apple/context_wrapper.h new file mode 100644 index 000000000..6522d641a --- /dev/null +++ b/llarp/apple/context_wrapper.h @@ -0,0 +1,94 @@ +#pragma once + +// C-linkage wrappers for interacting with a lokinet context, so that we can call them from Swift +// code (which currently doesn't support C++ interoperability at all). + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + + /// C callback function for us to invoke when we need to write a packet + typedef void(packet_writer_callback)(int af, const void* data, size_t size, void* ctx); + + /// C callback function to invoke once we are ready to start receiving packets + typedef void(start_reading_callback)(void* ctx); + + /// C callback that bridges things into NSLog + typedef void(ns_logger_callback)(const char* msg); + + /// Initializes a lokinet instance by initializing various objects and loading the configuration + /// (if {config_dir}/lokinet.ini exists). Does not actually start lokinet (call llarp_apple_start + /// for that). + /// + /// Returns NULL if there was a problem initializing/loading the configuration, otherwise returns + /// an opaque void pointer that should be passed into the other llarp_apple_* functions. + /// + /// \param logger a logger callback that we pass log messages to to relay them (i.e. via NSLog). + /// + /// \param config_dir the lokinet configuration directory where lokinet.ini can be and the various + /// other lokinet state files go. + /// + /// \param default_bootstrap the path to the default bootstrap.signed included in installation, + /// which will be used if no explicit bootstrap is set in the config file. + /// + /// \param ip - char buffer where we will write the primary tunnel IP address as a string such as + /// "172.16.0.0". Will write up to 16 characters (including the null terminator). This will be + /// the tunnel IP from the lokinet.ini, if it exists and specifies a range, otherwise we'll + /// configure lokinet to use a currently-unused range and return that. + /// + /// \param netmask the tunnel netmask as a string such as "255.255.0.0". Will write up to 16 + /// characters (including the null terminator). + /// + /// \param dns the DNS address that should be configured to query lokinet, as a string such as + /// "172.16.0.1". Will write up to 16 characters (including the null terminator). + void* + llarp_apple_init( + ns_logger_callback ns_logger, + const char* config_dir, + const char* default_bootstrap, + char* ip, + char* netmask, + char* dns); + + /// Starts the lokinet instance in a new thread. + /// + /// \param packet_writer C function callback that will be called when we need to write a packet to + /// the packet tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, the size + /// of the data in bytes, and the opaque callback_context pointer. + /// + /// \param start_reading C function callback that will be called when lokinet is setup and ready + /// to start receiving packets from the packet tunnel. This should set up the read handler to + /// deliver packets via llarp_apple_incoming. This is called with a single argument of the opaque + /// callback_context pointer. + /// + /// \param callback_context Opaque pointer that is passed into the packet_writer and start_reading + /// callback, intended to allow context to be passed through to the callbacks. This code does + /// nothing with this pointer aside from passing it through to callbacks. + /// + /// \returns 0 on succesful startup, -1 on failure. + int + llarp_apple_start( + void* lokinet, + packet_writer_callback packet_writer, + start_reading_callback start_reading, + void* callback_context); + + /// 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). + int + llarp_apple_incoming(void* lokinet, const void* bytes, 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. + void + llarp_apple_shutdown(void* lokinet); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/llarp/apple/vpn_interface.cpp b/llarp/apple/vpn_interface.cpp new file mode 100644 index 000000000..079e24aa9 --- /dev/null +++ b/llarp/apple/vpn_interface.cpp @@ -0,0 +1,52 @@ + +#include "vpn_interface.hpp" +#include "context.hpp" + +namespace llarp::apple +{ + VPNInterface::VPNInterface( + Context& ctx, packet_write_callback packet_writer, on_readable_callback on_readable) + : m_PacketWriter{std::move(packet_writer)}, m_OnReadable{std::move(on_readable)} + { + ctx.loop->call_soon([this] { m_OnReadable(*this); }); + } + + bool + VPNInterface::OfferReadPacket(const llarp_buffer_t& buf) + { + llarp::net::IPPacket pkt; + if (!pkt.Load(buf)) + return false; + m_ReadQueue.tryPushBack(std::move(pkt)); + return true; + } + + int + VPNInterface::PollFD() const + { + return -1; + } + + std::string + VPNInterface::IfName() const + { + return ""; + } + + net::IPPacket + VPNInterface::ReadNextPacket() + { + net::IPPacket pkt{}; + if (not m_ReadQueue.empty()) + pkt = m_ReadQueue.popFront(); + return pkt; + } + + bool + VPNInterface::WritePacket(net::IPPacket pkt) + { + int af_family = pkt.IsV6() ? AF_INET6 : AF_INET; + return m_PacketWriter(af_family, pkt.buf, pkt.sz); + } + +} // namespace llarp::apple diff --git a/llarp/apple/vpn_interface.hpp b/llarp/apple/vpn_interface.hpp new file mode 100644 index 000000000..c1dff8dbf --- /dev/null +++ b/llarp/apple/vpn_interface.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include +#include + +namespace llarp::apple +{ + struct Context; + + class VPNInterface final : public vpn::NetworkInterface, + public std::enable_shared_from_this + { + public: + using packet_write_callback = std::function; + using on_readable_callback = std::function; + + explicit VPNInterface( + Context& ctx, packet_write_callback packet_writer, on_readable_callback on_readable); + + // Method to call when a packet has arrived to deliver the packet to lokinet + bool + OfferReadPacket(const llarp_buffer_t& buf); + + int + PollFD() const override; + + std::string + IfName() const override; + + net::IPPacket + ReadNextPacket() override; + + bool + WritePacket(net::IPPacket pkt) override; + + private: + // Function for us to call when we have a packet to emit. Should return true if the packet was + // handed off to the OS successfully. + packet_write_callback m_PacketWriter; + + // Called when we are ready to start reading packets + on_readable_callback m_OnReadable; + + static inline constexpr auto PacketQueueSize = 1024; + + thread::Queue m_ReadQueue{PacketQueueSize}; + }; + +} // namespace llarp::apple diff --git a/llarp/apple/vpn_platform.hpp b/llarp/apple/vpn_platform.hpp new file mode 100644 index 000000000..72018b509 --- /dev/null +++ b/llarp/apple/vpn_platform.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include "vpn_interface.hpp" + +namespace llarp::apple +{ + class VPNPlatform final : public vpn::Platform + { + public: + explicit VPNPlatform( + Context& ctx, + VPNInterface::packet_write_callback packet_writer, + VPNInterface::on_readable_callback on_readable) + : m_Context{ctx} + , m_PacketWriter{std::move(packet_writer)} + , m_OnReadable{std::move(on_readable)} + {} + + std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override + { + return std::make_shared(m_Context, m_PacketWriter, m_OnReadable); + } + + private: + Context& m_Context; + VPNInterface::packet_write_callback m_PacketWriter; + VPNInterface::on_readable_callback m_OnReadable; + }; + +} // namespace llarp::apple From 2964051f0da48b64cc406ff2297031cd086ff787 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 25 Aug 2021 20:49:49 -0300 Subject: [PATCH 14/45] Remove swift version (do not squash) Don't squash this commit so that the swift version stays around in history in case we need to resurrect it again some day (i.e. when Apple decides to kill off Objective-C support). --- llarp/apple/PacketTunnelProvider.swift | 129 ------------------------- 1 file changed, 129 deletions(-) delete mode 100644 llarp/apple/PacketTunnelProvider.swift diff --git a/llarp/apple/PacketTunnelProvider.swift b/llarp/apple/PacketTunnelProvider.swift deleted file mode 100644 index 1cee28bed..000000000 --- a/llarp/apple/PacketTunnelProvider.swift +++ /dev/null @@ -1,129 +0,0 @@ -/// Lokinet network extension swift glue layer - -import NetworkExtension - -enum LokinetError: Error { - case runtimeError(String) -} - -func packet_writer(af: Int32, data: UnsafeRawPointer?, size: Int, ctx: UnsafeMutableRawPointer?) { - if ctx == nil || data == nil { - return - } - let tunnel = ctx!.assumingMemoryBound(to: PacketTunnelProvider.self).pointee - - let packet = NEPacket( - data: Data(bytes: data!, count: 1), - protocolFamily: sa_family_t(af)) - tunnel.packetFlow.writePacketObjects([packet]) -} - - -func start_packet_reader(ctx: UnsafeMutableRawPointer?) { - let tunnel = ctx?.assumingMemoryBound(to: PacketTunnelProvider.self).pointee - tunnel?.readHandler() -} - - -class PacketTunnelProvider: NEPacketTunnelProvider { - - var lokinet: UnsafeMutableRawPointer? - - func readHandler() { - packetFlow.readPacketObjects() { (packets: [NEPacket]) in - if self.lokinet == nil { - return - } - - for p in packets { - p.data.withUnsafeBytes { (buf: UnsafeRawBufferPointer) -> Void in - llarp_apple_incoming(self.lokinet, buf.baseAddress!, buf.count) - } - } - - self.readHandler() - } - } - - override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { - - var ip_buf = Array(repeating: 0, count: 16) - var mask_buf = Array(repeating: 0, count: 16) - var dns_buf = Array(repeating: 0, count: 16) - - lokinet = llarp_apple_init(NSHomeDirectory(), &ip_buf, &mask_buf, &dns_buf) - if lokinet == nil { - NSLog("Lokinet initialization failed!") - completionHandler(LokinetError.runtimeError("Lokinet initialization failed")) - return - } - - let ip = String(cString: ip_buf) - let mask = String(cString: mask_buf) - let dns_addr = String(cString: dns_buf) - - NSLog("Lokinet configured with address %s/%s, dns %s", ip, mask, dns_addr) - - let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1") - settings.ipv4Settings = NEIPv4Settings(addresses: [ip], subnetMasks: [mask]) - let dns = NEDNSSettings(servers: [dns_addr]) - dns.domainName = "localhost.loki" - dns.matchDomains = ["snode", "loki"] - dns.matchDomainsNoSearch = true - dns.searchDomains = [] - settings.dnsSettings = dns - - let condition = NSCondition() - condition.lock() - defer { condition.unlock() } - - var system_error: Error? - - setTunnelNetworkSettings(settings) { error in - system_error = error - condition.signal() - } - - condition.wait() - - if let error = system_error { - NSLog("Failed to set up tunnel: %s", error.localizedDescription) - lokinet = nil - completionHandler(error) - return - } - - var myself = self - let start_ret = llarp_apple_start(lokinet, packet_writer, start_packet_reader, &myself) - if start_ret != 0 { - NSLog("Lokinet failed to start!") - lokinet = nil - completionHandler(LokinetError.runtimeError("Lokinet failed to start")) - return - } - completionHandler(nil) - } - - override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { - if lokinet != nil { - llarp_apple_shutdown(lokinet) - lokinet = nil - } - completionHandler() - } - - override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { - if let handler = completionHandler { - handler(messageData) - } - } - - override func sleep(completionHandler: @escaping () -> Void) { - // FIXME - do we need to kick lokinet here? - completionHandler() - } - - override func wake() { - // FIXME - do we need to kick lokinet here? - } -} From e39c473c886cb7f1af69a00ada2dc569ea93417c Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 25 Aug 2021 20:54:08 -0300 Subject: [PATCH 15/45] format.sh: support macports clang-format macports names it clang-format-mp-N to avoid clashing with a system-installed one. --- contrib/format.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/format.sh b/contrib/format.sh index 785d9ba54..e514590bd 100755 --- a/contrib/format.sh +++ b/contrib/format.sh @@ -3,6 +3,9 @@ CLANG_FORMAT_DESIRED_VERSION=11 binary=$(which clang-format-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null) +if [ $? -ne 0 ]; then + binary=$(which clang-format-mp-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null) +fi if [ $? -ne 0 ]; then binary=$(which clang-format 2>/dev/null) if [ $? -ne 0 ]; then From fec3598e16a7db414ea5bfbd5a94b4b9bafafc9a Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 26 Aug 2021 11:15:21 -0300 Subject: [PATCH 16/45] Remove no-longer-used framework.mm --- llarp/apple/framework.mm | 260 --------------------------------------- 1 file changed, 260 deletions(-) delete mode 100644 llarp/apple/framework.mm diff --git a/llarp/apple/framework.mm b/llarp/apple/framework.mm deleted file mode 100644 index be7af8022..000000000 --- a/llarp/apple/framework.mm +++ /dev/null @@ -1,260 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -const llarp::SockAddr DefaultDNSBind{"127.0.0.1:1153"}; -const llarp::SockAddr DefaultUpstreamDNS{"9.9.9.9:53"}; - -namespace llarp::apple -{ - struct FrameworkContext : public llarp::Context - { - explicit FrameworkContext(NEPacketTunnelProvider* tunnel); - - ~FrameworkContext() - {} - - std::shared_ptr - makeVPNPlatform() override; - - void - Start(std::string_view bootstrap, std::string exit); - - private: - NEPacketTunnelProvider* const m_Tunnel; - std::unique_ptr m_Runner; - }; - - class VPNInterface final : public vpn::NetworkInterface - { - NEPacketTunnelProvider* const m_Tunnel; - - static inline constexpr auto PacketQueueSize = 1024; - - thread::Queue m_ReadQueue; - - void - OfferReadPacket(NSData* data) - { - llarp::net::IPPacket pkt; - const llarp_buffer_t buf{static_cast(data.bytes), data.length}; - if (pkt.Load(buf)) - { - m_ReadQueue.tryPushBack(std::move(pkt)); - } - else - { - LogError("invalid IP packet: ", llarp::buffer_printer(DataAsStringView(data))); - } - } - - public: - explicit VPNInterface(NEPacketTunnelProvider* tunnel, llarp::Context* context) - : m_Tunnel{tunnel}, m_ReadQueue{PacketQueueSize} - { - context->loop->call_soon([this]() { Read(); }); - } - - void - HandleReadEvent(NSArray* packets, NSArray* protos) - { - NSUInteger num = [packets count]; - for (NSUInteger idx = 0; idx < num; ++idx) - { - NSData* pkt = [packets objectAtIndex:idx]; - OfferReadPacket(pkt); - } - Read(); - } - - void - Read() - { - auto handler = [this](NSArray* packets, NSArray* protos) { - HandleReadEvent(packets, protos); - }; - [m_Tunnel.packetFlow readPacketsWithCompletionHandler:handler]; - } - - int - PollFD() const override - { - return -1; - } - - std::string - IfName() const override - { - return ""; - } - - net::IPPacket - ReadNextPacket() override - { - net::IPPacket pkt{}; - if (not m_ReadQueue.empty()) - pkt = m_ReadQueue.popFront(); - return pkt; - } - - bool - WritePacket(net::IPPacket pkt) override - { - NSNumber* fam = [NSNumber numberWithInteger:(pkt.IsV6() ? AF_INET6 : AF_INET)]; - void* pktbuf = pkt.buf; - const size_t pktsz = pkt.sz; - NSData* datapkt = [NSData dataWithBytesNoCopy:pktbuf length:pktsz]; - return [m_Tunnel.packetFlow writePackets:@[datapkt] withProtocols:@[fam]]; - } - }; - - class VPNPlatform final : public vpn::Platform - { - NEPacketTunnelProvider* const m_Tunnel; - Context* const m_Context; - - public: - explicit VPNPlatform(NEPacketTunnelProvider* tunnel, Context* context) - : m_Tunnel{tunnel}, m_Context{context} - {} - - std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override - { - return std::make_shared(m_Tunnel, m_Context); - } - }; - - FrameworkContext::FrameworkContext(NEPacketTunnelProvider* tunnel) - : llarp::Context{}, m_Tunnel{tunnel} - {} - - void - FrameworkContext::Start(std::string_view bootstrap, std::string exit) - { - std::promise result; - - m_Runner = - std::make_unique([&result, bootstrap = std::string{bootstrap}, exit, this]() { - const RuntimeOptions opts{}; - try - { - auto config = llarp::Config::NetworkExtensionConfig(exit); - config->bootstrap.files.emplace_back(bootstrap); - config->dns.m_bind = DefaultDNSBind; - config->dns.m_upstreamDNS.push_back(DefaultUpstreamDNS); - Configure(std::move(config)); - Setup(opts); - } - catch (std::exception&) - { - result.set_exception(std::current_exception()); - return; - } - result.set_value(); - Run(opts); - }); - - auto ftr = result.get_future(); - ftr.get(); - } - - std::shared_ptr - FrameworkContext::makeVPNPlatform() - { - return std::make_shared(m_Tunnel, this); - } -} - -struct ContextWrapper -{ - std::unique_ptr m_Context; - - public: - explicit ContextWrapper(NEPacketTunnelProvider* tunnel) - : m_Context{std::make_unique(tunnel)} - {} - - void - Start(std::string_view bootstrap, std::string exit) - { - llarp::LogContext::Instance().logStream.reset(new llarp::NSLogStream{}); - m_Context->Start(std::move(bootstrap), std::move(exit)); - } - - void - Stop() - { - m_Context->CloseAsync(); - m_Context->Wait(); - } -}; - -@implementation LLARPPacketTunnel - -- (void)startTunnelWithOptions:(NSDictionary*)options - completionHandler:(void (^)(NSError*))completionHandler -{ - llarp::huint32_t addr_{}; - llarp::huint32_t mask_{}; - if (auto maybe = llarp::FindFreeRange()) - { - addr_ = llarp::net::TruncateV6(maybe->addr); - mask_ = llarp::net::TruncateV6(maybe->netmask_bits); - } - NSString* addr = StringToNSString(addr_.ToString()); - NSString* mask = StringToNSString(mask_.ToString()); - llarp::huint32_t dnsaddr_{addr_ & mask_}; - NSString* dnsaddr = StringToNSString(dnsaddr_.ToString()); - NSLog(@"%@", dnsaddr); - - NSBundle* main = [NSBundle mainBundle]; - NSString* res = [main pathForResource:@"bootstrap" ofType:@"signed"]; - NSData* path = [res dataUsingEncoding:NSUTF8StringEncoding]; - - m_Context = new ContextWrapper{self}; - m_Context->Start(DataAsStringView(path), "exit.loki"); - - NEPacketTunnelNetworkSettings* settings = - [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"]; - NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[dnsaddr]]; - dns.domainName = @"localhost.loki"; - dns.matchDomains = @[@"*.snode", @"*.loki"]; - dns.matchDomainsNoSearch = true; - dns.searchDomains = @[]; - // dns.dnsProtocol = NEDNSProtocolCleartext; - NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[addr] - subnetMasks:@[@"255.255.255.255"]]; - ipv4.includedRoutes = @[[NEIPv4Route defaultRoute]]; - // ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:addr subnetMask:mask]]; - settings.IPv4Settings = ipv4; - settings.DNSSettings = dns; - [self setTunnelNetworkSettings:settings completionHandler:completionHandler]; -} - -- (void)stopTunnelWithReason:(NEProviderStopReason)reason - completionHandler:(void (^)(void))completionHandler -{ - if (m_Context) - { - m_Context->Stop(); - delete m_Context; - m_Context = nullptr; - } - completionHandler(); -} - -- (void)handleAppMessage:(NSData*)messageData - completionHandler:(void (^)(NSData* responseData))completionHandler -{ - const auto data = DataAsStringView(messageData); - completionHandler(StringViewToData("ok")); -} -@end From 58da228f620fe7f4ab191306d287c41d8c410707 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 26 Aug 2021 11:33:46 -0300 Subject: [PATCH 17/45] Generate a default client lokinet.ini on startup if it doesn't exist Thus when a user goes looking for it they'll find the (commented out) default in the right place and can edit it. (That right place is: ~/Library/Containers/com.loki-project.lokinet.network-extension/Data/lokinet.ini) --- llarp/apple/context_wrapper.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index bd781fa89..3d1eb2a37 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -40,9 +40,9 @@ llarp_apple_init( { auto config_dir = fs::u8path(config_dir_); auto config = std::make_shared(config_dir); - std::optional config_path = config_dir / "lokinet.ini"; - if (!fs::exists(*config_path)) - config_path.reset(); + fs::path config_path = config_dir / "lokinet.ini"; + if (!fs::exists(config_path)) + llarp::ensureConfig(config_dir, config_path, /*overwrite=*/ false, /*router=*/ false); config->Load(config_path); // If no range is specified then go look for a free one, set that in the config, and then return From 3527c9cdb54786e40896870965c74e6549d77361 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 26 Aug 2021 11:38:17 -0300 Subject: [PATCH 18/45] Remove more unused dns-proxy files --- contrib/macos/LokinetDNSProxy.Info.plist.in | 40 ----- .../macos/lokinet-dnsproxy.entitlements.plist | 29 ---- .../macos/lokinet-dnsproxy.provisionprofile | Bin 17128 -> 0 bytes llarp/apple/dnsproxy.mm | 154 ------------------ 4 files changed, 223 deletions(-) delete mode 100644 contrib/macos/LokinetDNSProxy.Info.plist.in delete mode 100644 contrib/macos/lokinet-dnsproxy.entitlements.plist delete mode 100644 contrib/macos/lokinet-dnsproxy.provisionprofile delete mode 100644 llarp/apple/dnsproxy.mm diff --git a/contrib/macos/LokinetDNSProxy.Info.plist.in b/contrib/macos/LokinetDNSProxy.Info.plist.in deleted file mode 100644 index 522b476ec..000000000 --- a/contrib/macos/LokinetDNSProxy.Info.plist.in +++ /dev/null @@ -1,40 +0,0 @@ - - - - - CFBundleDisplayName - Lokinet - - CFBundleExecutable - lokinet-dnsproxy - - CFBundleIdentifier - com.loki-project.lokinet.dns-proxy - - CFBundleInfoDictionaryVersion - 6.0 - - CFBundlePackageType - XPC! - - CFBundleName - lokinet - - CFBundleVersion - @LOKINET_VERSION@ - - ITSAppUsesNonExemptEncryption - - - LSMinimumSystemVersion - 11.0 - - NSExtension - - NSExtensionPointIdentifier - com.apple.networkextension.dns-proxy - NSExtensionPrincipalClass - DNSProvider - - - diff --git a/contrib/macos/lokinet-dnsproxy.entitlements.plist b/contrib/macos/lokinet-dnsproxy.entitlements.plist deleted file mode 100644 index fa43bbd2b..000000000 --- a/contrib/macos/lokinet-dnsproxy.entitlements.plist +++ /dev/null @@ -1,29 +0,0 @@ - - - - - com.apple.application-identifier - SUQ8J2PCT7.com.loki-project.lokinet.dns-proxy - - com.apple.developer.networking.networkextension - - dns-proxy - - - com.apple.developer.team-identifier - SUQ8J2PCT7 - - com.apple.security.app-sandbox - - - com.apple.security.get-task-allow - - - com.apple.security.network.client - - - com.apple.security.network.server - - - - diff --git a/contrib/macos/lokinet-dnsproxy.provisionprofile b/contrib/macos/lokinet-dnsproxy.provisionprofile deleted file mode 100644 index 87cd403bb4919366f2e767f28b38cb0f168a60c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17128 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 Z?Z9=CJE$b@rw5OI`eOO=&%e0*zX6(qnR);K diff --git a/llarp/apple/dnsproxy.mm b/llarp/apple/dnsproxy.mm deleted file mode 100644 index 56663118c..000000000 --- a/llarp/apple/dnsproxy.mm +++ /dev/null @@ -1,154 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include - -struct DNSImpl -{ - oxenmq::OxenMQ m_MQ; - std::optional m_Conn; - - explicit DNSImpl(oxenmq::address rpc) - { - m_MQ.start(); - m_MQ.connect_remote( - rpc, [this](auto conn) { m_Conn = conn; }, nullptr); - } - - bool - ShouldHookFlow(NEAppProxyFlow* flow) const - { - LogInfo(NSObjectToString(flow)); - return true; - } - - void - RelayDNSData(NEAppProxyUDPFlow* flow, NWEndpoint* remote, NSData* data) - { - if (not m_Conn) - return; - auto view = DataAsStringView(data); - - llarp_buffer_t buf{view}; - llarp::dns::MessageHeader hdr{}; - if (not hdr.Decode(&buf)) - return; - llarp::dns::Message msg{hdr}; - if (not msg.Decode(&buf)) - return; - llarp::util::StatusObject request{ - {"qname", msg.questions[0].qname}, {"qtype", msg.questions[0].qtype}}; - m_MQ.request( - *m_Conn, - "llarp.dns_query", - [flow, remote, msg = std::make_shared(std::move(msg))]( - bool good, std::vector parts) { - auto closeHandler = [flow](NSError* err) { - [flow closeWriteWithError:err]; - [flow closeReadWithError:err]; - }; - if (good and parts.size() == 1) - { - try - { - const auto obj = nlohmann::json::parse(parts[0]); - const auto result = obj["result"]; - if (const auto itr = result.find("answers"); itr != result.end()) - { - for (const auto& result : (*itr)) - { - llarp::dns::RR_RData_t rdata; - if (const auto data_itr = result.find("rdata"); data_itr != result.end()) - { - const auto data = data_itr->get(); - rdata.resize(data.size()); - std::copy_n(data.begin(), data.size(), rdata.begin()); - } - else - continue; - - msg->answers.emplace_back( - result["name"].get(), - result["type"].get(), - rdata); - } - } - } - catch (std::exception& ex) - { - LogError("dns query failed: ", ex.what()); - return; - } - const auto buf = msg->ToBuffer(); - NSData* data = StringViewToData( - std::string_view{reinterpret_cast(buf.buf.get()), buf.sz}); - [flow writeDatagrams:@[data] sentByEndpoints:@[remote] completionHandler:closeHandler]; - } - else - closeHandler(nullptr); - }, - request.dump()); - } - - void - HandleUDPFlow(NEAppProxyUDPFlow* flow) - { - auto handler = - [this, flow]( - NSArray* datagrams, NSArray* remoteEndpoints, NSError* error) { - if (error) - return; - NSInteger num = [datagrams count]; - for (NSInteger idx = 0; idx < num; ++idx) - { - RelayDNSData(flow, [remoteEndpoints objectAtIndex:idx], [datagrams objectAtIndex:idx]); - } - }; - [flow readDatagramsWithCompletionHandler:handler]; - } -}; - -@implementation DNSProvider - -- (void)startProxyWithOptions:(NSDictionary*)options - completionHandler:(void (^)(NSError* error))completionHandler -{ - m_Impl = new DNSImpl{oxenmq::address{"tcp://127.0.0.1:1190"}}; - completionHandler(nil); -} - -- (void)stopProxyWithReason:(NEProviderStopReason)reason - completionHandler:(void (^)(void))completionHandler -{ - if (m_Impl) - { - delete m_Impl; - m_Impl = nullptr; - } - completionHandler(); -} - -- (BOOL)handleNewFlow:(NEAppProxyFlow*)flow -{ - if (not [flow isKindOfClass:[NEAppProxyUDPFlow class]]) - return NO; - if (m_Impl->ShouldHookFlow(flow)) - { - NEAppProxyUDPFlow* udp = (NEAppProxyUDPFlow*)flow; - auto handler = [impl = m_Impl, udp](NSError* err) { - if (err) - return; - impl->HandleUDPFlow(udp); - }; - [flow openWithLocalEndpoint:nil completionHandler:handler]; - return YES; - } - return NO; -} - -@end From 9afa95cd7a3c078a35e71d5bd70083b0e77ee799 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 26 Aug 2021 12:09:35 -0300 Subject: [PATCH 19/45] Remove unused/empty/no longer used apple headers --- llarp/apple.hpp | 40 ---------------------------------------- llarp/vpn/apple.hpp | 0 2 files changed, 40 deletions(-) delete mode 100644 llarp/apple.hpp delete mode 100644 llarp/vpn/apple.hpp diff --git a/llarp/apple.hpp b/llarp/apple.hpp deleted file mode 100644 index dc35a9d95..000000000 --- a/llarp/apple.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#ifdef __APPLE__ -#include -#include -#include - -static std::string_view -DataAsStringView(NSData* data) -{ - return std::string_view{reinterpret_cast(data.bytes), data.length}; -} - -static NSData* -StringViewToData(std::string_view data) -{ - const char* ptr = data.data(); - const size_t sz = data.size(); - return [NSData dataWithBytes:ptr length:sz]; -} - -static NSString* -StringToNSString(std::string data) -{ - NSData* ptr = StringViewToData(std::string_view{data}); - return [[NSString alloc] initWithData:ptr encoding:NSUTF8StringEncoding]; -} - -static std::string -NSStringToString(NSString* str) -{ - return std::string{[str UTF8String]}; -} - -static std::string -NSObjectToString(NSObject* obj) -{ - return NSStringToString([NSString stringWithFormat:@"%@", obj]); -} - -#endif diff --git a/llarp/vpn/apple.hpp b/llarp/vpn/apple.hpp deleted file mode 100644 index e69de29bb..000000000 From c74dcba463fe2e56fa268805d891f860f7045fcb Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Mon, 30 Aug 2021 10:10:24 -0300 Subject: [PATCH 20/45] Add lokinet subnet to default routes Mac doesn't route to a tunnel's ip range by default. WTF. --- llarp/apple/PacketTunnelProvider.m | 1 + 1 file changed, 1 insertion(+) diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m index b203095f9..1255f61c1 100644 --- a/llarp/apple/PacketTunnelProvider.m +++ b/llarp/apple/PacketTunnelProvider.m @@ -96,6 +96,7 @@ void start_packet_reader(void* ctx) { dns.searchDomains = @[]; NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[ip] subnetMasks:@[mask]]; + ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:ip subnetMask: mask]]; settings.IPv4Settings = ipv4; settings.DNSSettings = dns; [self setTunnelNetworkSettings:settings completionHandler:^(NSError* err) { From e84390748d9a229261309af745c729573670f54d Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Mon, 30 Aug 2021 14:55:33 -0300 Subject: [PATCH 21/45] Add RouteManager; make exit on/off work --- llarp/apple/CMakeLists.txt | 2 +- llarp/apple/PacketTunnelProvider.m | 170 +++++++++++++++++++++++++++-- llarp/apple/context.hpp | 5 +- llarp/apple/context_wrapper.cpp | 45 ++++---- llarp/apple/context_wrapper.h | 132 ++++++++++++++-------- llarp/apple/route_manager.cpp | 61 +++++++++++ llarp/apple/route_manager.hpp | 46 ++++++++ llarp/apple/vpn_platform.hpp | 9 +- 8 files changed, 390 insertions(+), 80 deletions(-) create mode 100644 llarp/apple/route_manager.cpp create mode 100644 llarp/apple/route_manager.hpp diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt index 8344e90a1..69a356020 100644 --- a/llarp/apple/CMakeLists.txt +++ b/llarp/apple/CMakeLists.txt @@ -15,7 +15,7 @@ find_library(COREFOUNDATION CoreFoundation REQUIRED) target_sources(lokinet-util PRIVATE apple_logger.cpp) target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) -target_sources(lokinet-platform PRIVATE vpn_interface.cpp context_wrapper.cpp) +target_sources(lokinet-platform PRIVATE vpn_interface.cpp route_manager.cpp context_wrapper.cpp) add_executable(lokinet-extension MACOSX_BUNDLE PacketTunnelProvider.m diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m index 1255f61c1..56ef0ca22 100644 --- a/llarp/apple/PacketTunnelProvider.m +++ b/llarp/apple/PacketTunnelProvider.m @@ -7,6 +7,8 @@ NSString* error_domain = @"com.loki-project.lokinet"; @interface LLARPPacketTunnel : NEPacketTunnelProvider { void* lokinet; + @public NEPacketTunnelNetworkSettings* settings; + @public NEIPv4Route* tun_route4; } - (void)startTunnelWithOptions:(NSDictionary*)options @@ -20,6 +22,8 @@ NSString* error_domain = @"com.loki-project.lokinet"; - (void)readPackets; +- (void)updateNetworkSettings; + @end void nslogger(const char* msg) { NSLog(@"%s", msg); } @@ -42,6 +46,97 @@ void start_packet_reader(void* ctx) { [t readPackets]; } +void add_ipv4_route(const char* addr, const char* netmask, void* ctx) { + NEIPv4Route* route = [[NEIPv4Route alloc] + initWithDestinationAddress: [NSString stringWithUTF8String:addr] + subnetMask: [NSString stringWithUTF8String:netmask]]; + + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + for (NEIPv4Route* r in t->settings.IPv4Settings.includedRoutes) + if ([r.destinationAddress isEqualToString:route.destinationAddress] && + [r.destinationSubnetMask isEqualToString:route.destinationSubnetMask]) + return; // Already in the settings, nothing to add. + + t->settings.IPv4Settings.includedRoutes = + [t->settings.IPv4Settings.includedRoutes arrayByAddingObject:route]; + + [t updateNetworkSettings]; +} + +void del_ipv4_route(const char* addr, const char* netmask, void* ctx) { + NEIPv4Route* route = [[NEIPv4Route alloc] + initWithDestinationAddress: [NSString stringWithUTF8String:addr] + subnetMask: [NSString stringWithUTF8String:netmask]]; + + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + NSMutableArray* routes = [NSMutableArray arrayWithArray:t->settings.IPv4Settings.includedRoutes]; + for (int i = 0; i < routes.count; i++) { + if ([routes[i].destinationAddress isEqualToString:route.destinationAddress] && + [routes[i].destinationSubnetMask isEqualToString:route.destinationSubnetMask]) { + [routes removeObjectAtIndex:i]; + i--; + } + } + + if (routes.count != t->settings.IPv4Settings.includedRoutes.count) { + t->settings.IPv4Settings.includedRoutes = routes; + [t updateNetworkSettings]; + } +} + +void add_ipv6_route(const char* addr, int prefix, void* ctx) { + NEIPv6Route* route = [[NEIPv6Route alloc] + initWithDestinationAddress: [NSString stringWithUTF8String:addr] + networkPrefixLength: [NSNumber numberWithInt:prefix]]; + + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + for (NEIPv6Route* r in t->settings.IPv6Settings.includedRoutes) + if ([r.destinationAddress isEqualToString:route.destinationAddress] && + [r.destinationNetworkPrefixLength isEqualToNumber:route.destinationNetworkPrefixLength]) + return; // Already in the settings, nothing to add. + + t->settings.IPv6Settings.includedRoutes = + [t->settings.IPv6Settings.includedRoutes arrayByAddingObject:route]; + + [t updateNetworkSettings]; +} +void del_ipv6_route(const char* addr, int prefix, void* ctx) { + NEIPv6Route* route = [[NEIPv6Route alloc] + initWithDestinationAddress: [NSString stringWithUTF8String:addr] + networkPrefixLength: [NSNumber numberWithInt:prefix]]; + + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + NSMutableArray* routes = [NSMutableArray arrayWithArray:t->settings.IPv6Settings.includedRoutes]; + for (int i = 0; i < routes.count; i++) { + if ([routes[i].destinationAddress isEqualToString:route.destinationAddress] && + [routes[i].destinationNetworkPrefixLength isEqualToNumber:route.destinationNetworkPrefixLength]) { + [routes removeObjectAtIndex:i]; + i--; + } + } + + if (routes.count != t->settings.IPv6Settings.includedRoutes.count) { + t->settings.IPv6Settings.includedRoutes = routes; + [t updateNetworkSettings]; + } +} +void add_default_route(void* ctx) { + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + + t->settings.IPv4Settings.includedRoutes = @[NEIPv4Route.defaultRoute]; + t->settings.IPv6Settings.includedRoutes = @[NEIPv6Route.defaultRoute]; + + [t updateNetworkSettings]; +} +void del_default_route(void* ctx) { + LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; + + t->settings.IPv4Settings.includedRoutes = @[t->tun_route4]; + t->settings.IPv4Settings.includedRoutes = @[]; // No tun_route6 yet. + + [t updateNetworkSettings]; +} + @implementation LLARPPacketTunnel - (void)readPackets @@ -63,21 +158,39 @@ void start_packet_reader(void* ctx) { char mask_buf[16]; char dns_buf[16]; - NSString* default_bootstrap = [[NSBundle mainBundle] pathForResource:@"bootstrap" ofType:@"signed"]; + NSString* default_bootstrap = [NSBundle.mainBundle pathForResource:@"bootstrap" ofType:@"signed"]; + NSString* home = NSHomeDirectory(); - lokinet = llarp_apple_init(nslogger, NSHomeDirectory().UTF8String, default_bootstrap.UTF8String, ip_buf, mask_buf, dns_buf); + llarp_apple_config conf = { + .config_dir = home.UTF8String, + .default_bootstrap = default_bootstrap.UTF8String, + .ns_logger = nslogger, + .packet_writer = packet_writer, + .start_reading = start_packet_reader, + .route_callbacks = { + .add_ipv4_route = add_ipv4_route, + .del_ipv4_route = del_ipv4_route, + .add_ipv6_route = add_ipv6_route, + .del_ipv6_route = del_ipv6_route, + .add_default_route = add_default_route, + .del_default_route = del_default_route + }, + }; + + lokinet = llarp_apple_init(&conf); if (!lokinet) { NSError *init_failure = [NSError errorWithDomain:error_domain code:500 userInfo:@{@"Error": @"Failed to initialize lokinet"}]; NSLog(@"%@", [init_failure localizedDescription]); return completionHandler(init_failure); } - NSString* ip = [[NSString alloc] initWithUTF8String:ip_buf]; - NSString* mask = [[NSString alloc] initWithUTF8String:mask_buf]; - NSString* dnsaddr = [[NSString alloc] initWithUTF8String:dns_buf]; - - NEPacketTunnelNetworkSettings* settings = - [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:@"127.0.0.1"]; + NSString* ip = [NSString stringWithUTF8String:conf.tunnel_ipv4_ip]; + NSString* mask = [NSString stringWithUTF8String:conf.tunnel_ipv4_netmask]; + NSString* dnsaddr = [NSString stringWithUTF8String:conf.tunnel_dns]; + + // 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:@[dnsaddr]]; dns.domainName = @"localhost.loki"; // In theory, matchDomains is supposed to be set to DNS suffixes that we resolve. This seems @@ -96,16 +209,21 @@ void start_packet_reader(void* ctx) { dns.searchDomains = @[]; NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[ip] subnetMasks:@[mask]]; - ipv4.includedRoutes = @[[[NEIPv4Route alloc] initWithDestinationAddress:ip subnetMask: mask]]; + tun_route4 = [[NEIPv4Route alloc] initWithDestinationAddress:ip subnetMask: mask]; + ipv4.includedRoutes = @[tun_route4]; settings.IPv4Settings = ipv4; settings.DNSSettings = dns; + __weak LLARPPacketTunnel* weakSelf = self; [self setTunnelNetworkSettings:settings completionHandler:^(NSError* err) { if (err) { NSLog(@"Failed to configure lokinet tunnel: %@", err); return completionHandler(err); } - - int start_ret = llarp_apple_start(lokinet, packet_writer, start_packet_reader, (__bridge void*) self); + LLARPPacketTunnel* strongSelf = weakSelf; + if (!strongSelf) + return completionHandler(nil); + + int start_ret = llarp_apple_start(strongSelf->lokinet, (__bridge void*) strongSelf); if (start_ret != 0) { NSError *start_failure = [NSError errorWithDomain:error_domain code:start_ret userInfo:@{@"Error": @"Failed to start lokinet"}]; NSLog(@"%@", start_failure); @@ -132,4 +250,34 @@ void start_packet_reader(void* ctx) { NSData* response = [NSData dataWithBytesNoCopy:"ok" length:3 freeWhenDone:NO]; completionHandler(response); } + +- (void)updateNetworkSettings +{ + self.reasserting = YES; + __weak LLARPPacketTunnel* weakSelf = self; + // Apple documentation says that setting network settings to nil isn't required before setting it + // to a new value. Apple lies: both end up with a routing table that looks exactly the same (from + // both `netstat -rn` and from everything that happens in `route -n monitor`), but if we don't + // call with nil first then everything fails to route to either lokinet *and* clearnet through the + // exit, so there is apparently some special magic internal Apple state that actually *does* + // require the tunnel settings being reset with nil first. + // + // Thanks for the accurate documentation, Apple. + // + [self setTunnelNetworkSettings:nil completionHandler:^(NSError* err) { + if (err) + NSLog(@"Failed to clear lokinet tunnel settings: %@", err); + LLARPPacketTunnel* strongSelf = weakSelf; + if (strongSelf) { + [weakSelf setTunnelNetworkSettings:strongSelf->settings completionHandler:^(NSError* err) { + LLARPPacketTunnel* strongSelf = weakSelf; + if (strongSelf) + strongSelf.reasserting = NO; + if (err) + NSLog(@"Failed to reconfigure lokinet tunnel settings: %@", err); + }]; + } + }]; +} + @end diff --git a/llarp/apple/context.hpp b/llarp/apple/context.hpp index e25090262..a3b92ad75 100644 --- a/llarp/apple/context.hpp +++ b/llarp/apple/context.hpp @@ -2,6 +2,7 @@ #include #include "vpn_platform.hpp" +#include "route_manager.hpp" namespace llarp::apple { @@ -10,7 +11,7 @@ namespace llarp::apple std::shared_ptr makeVPNPlatform() override { - return std::make_shared(*this, m_PacketWriter, m_OnReadable); + return std::make_shared(*this, m_PacketWriter, m_OnReadable, route_callbacks, callback_context); } // Callbacks that must be set for packet handling *before* calling Setup/Configure/Run; the main @@ -18,6 +19,8 @@ namespace llarp::apple // after construction. VPNInterface::packet_write_callback m_PacketWriter; VPNInterface::on_readable_callback m_OnReadable; + llarp_route_callbacks route_callbacks{}; + void* callback_context = nullptr; }; } // namespace llarp::apple diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index 3d1eb2a37..2ede9a498 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -19,6 +19,8 @@ namespace { llarp::apple::Context context; std::thread runner; + packet_writer_callback packet_writer; + start_reading_callback start_reading; std::weak_ptr iface; }; @@ -26,19 +28,13 @@ namespace } // namespace void* -llarp_apple_init( - ns_logger_callback ns_logger, - const char* config_dir_, - const char* default_bootstrap, - char* ip, - char* netmask, - char* dns) +llarp_apple_init(llarp_apple_config* appleconf) { - llarp::LogContext::Instance().logStream = std::make_unique(ns_logger); + llarp::LogContext::Instance().logStream = std::make_unique(appleconf->ns_logger); try { - auto config_dir = fs::u8path(config_dir_); + auto config_dir = fs::u8path(appleconf->config_dir); auto config = std::make_shared(config_dir); fs::path config_path = config_dir / "lokinet.ini"; if (!fs::exists(config_path)) @@ -59,10 +55,10 @@ llarp_apple_init( auto mask = llarp::net::TruncateV6(range.netmask_bits).ToString(); if (addr.size() > 15 || mask.size() > 15) throw std::runtime_error{"Unexpected non-IPv4 tunnel range configured"}; - std::strcpy(ip, addr.c_str()); - std::strcpy(netmask, mask.c_str()); + std::strcpy(appleconf->tunnel_ipv4_ip, addr.c_str()); + std::strcpy(appleconf->tunnel_ipv4_netmask, mask.c_str()); // XXX possibly DNS needs to be the .0 instead of the .1 because mac reasons? - std::strcpy(dns, addr.c_str()); + std::strcpy(appleconf->tunnel_dns, addr.c_str()); // 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. @@ -71,10 +67,16 @@ llarp_apple_init( // If no explicit bootstrap then set the system default one included with the app bundle if (config->bootstrap.files.empty()) - config->bootstrap.files.push_back(fs::u8path(default_bootstrap)); + config->bootstrap.files.push_back(fs::u8path(appleconf->default_bootstrap)); auto inst = std::make_unique(); inst->context.Configure(std::move(config)); + inst->context.route_callbacks = appleconf->route_callbacks; + + inst->packet_writer = appleconf->packet_writer; + inst->start_reading = appleconf->start_reading; + + return inst.release(); } catch (const std::exception& e) @@ -87,21 +89,22 @@ llarp_apple_init( int llarp_apple_start( void* lokinet, - packet_writer_callback packet_writer, - start_reading_callback start_reading, void* callback_context) { auto* inst = static_cast(lokinet); - inst->context.m_PacketWriter = [inst, packet_writer, callback_context]( - int af_family, void* data, size_t size) { - packet_writer(af_family, data, size, callback_context); - return true; + + inst->context.callback_context = callback_context; + + inst->context.m_PacketWriter = [inst, callback_context]( + int af_family, void* data, size_t size) { + inst->packet_writer(af_family, data, size, callback_context); + return true; }; inst->context.m_OnReadable = - [inst, start_reading, callback_context](llarp::apple::VPNInterface& iface) { + [inst, callback_context](llarp::apple::VPNInterface& iface) { inst->iface = iface.weak_from_this(); - start_reading(callback_context); + inst->start_reading(callback_context); }; std::promise result; diff --git a/llarp/apple/context_wrapper.h b/llarp/apple/context_wrapper.h index 6522d641a..279dd7cf1 100644 --- a/llarp/apple/context_wrapper.h +++ b/llarp/apple/context_wrapper.h @@ -12,70 +12,112 @@ extern "C" #include /// C callback function for us to invoke when we need to write a packet - typedef void(packet_writer_callback)(int af, const void* data, size_t size, void* ctx); + typedef void(*packet_writer_callback)(int af, const void* data, size_t size, void* ctx); /// C callback function to invoke once we are ready to start receiving packets - typedef void(start_reading_callback)(void* ctx); + typedef void(*start_reading_callback)(void* ctx); /// C callback that bridges things into NSLog - typedef void(ns_logger_callback)(const char* msg); + typedef void(*ns_logger_callback)(const char* msg); + + /// C callbacks to add/remove specific and default routes to the tunnel + typedef void(*llarp_route_ipv4_callback)(const char* addr, const char* netmask, void* ctx); + typedef void(*llarp_route_ipv6_callback)(const char* addr, int prefix, void* ctx); + typedef void(*llarp_default_route_callback)(void* ctx); + typedef struct llarp_route_callbacks { + /// Callback invoked to set up an IPv4 range that should be routed through the tunnel + /// interface. Called with the address and netmask. + llarp_route_ipv4_callback add_ipv4_route; + + /// Callback invoked to set the tunnel as the default IPv4 route. + llarp_default_route_callback add_ipv4_default_route; + + /// Callback invoked to remove a specific range from the tunnel IPv4 routes. Called with the + /// address and netmask. + llarp_route_ipv4_callback del_ipv4_route; + + /// Callback invoked to set up an IPv6 range that should be routed through the tunnel + /// interface. Called with the address and netmask. + llarp_route_ipv6_callback add_ipv6_route; + + /// Callback invoked to remove a specific range from the tunnel IPv6 routes. Called with the + /// address and netmask. + llarp_route_ipv6_callback del_ipv6_route; + + /// Callback invoked to set the tunnel as the default IPv4/IPv6 route. + llarp_default_route_callback add_default_route; + + /// Callback invoked to remove the tunnel as the default IPv4/IPv6 route. + llarp_default_route_callback del_default_route; + } llarp_route_callbacks; + + /// Pack of crap to be passed into llarp_apple_init to initialize + typedef struct llarp_apple_config + { + /// lokinet configuration directory, expected to be the application-specific "home" directory, + /// which is where state files are stored and the lokinet.ini will be loaded (or created if it + /// doesn't exist). + const char* config_dir; + /// path to the default bootstrap.signed file included in installation, which will be used by + /// default when no specific bootstrap is in the config file. + const char* default_bootstrap; + /// llarp_apple_init writes the IP address for the primary tunnel IP address here, + /// null-terminated. + char tunnel_ipv4_ip[16]; + /// llarp_apple_init writes the netmask of the tunnel address here, null-terminated. + char tunnel_ipv4_netmask[16]; + /// The DNS server IPv4 address the OS should use. Null-terminated. + char tunnel_dns[16]; + + /// \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 + /// llarp_apple_start when invoked. + /// @{ + + /// simple wrapper around NSLog for lokinet message logging + ns_logger_callback ns_logger; + + /// C function callback that will be called when we need to write a packet to the packet + /// tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, and the size of + /// the data in bytes. + packet_writer_callback packet_writer; + + /// C function callback that will be called when lokinet is setup and ready to start receiving + /// packets from the packet tunnel. This should set up the read handler to deliver packets + /// via llarp_apple_incoming. + start_reading_callback start_reading; + + /// Callbacks invoked to add/remove routes to the tunnel. + llarp_route_callbacks route_callbacks; + + /// @} + } llarp_apple_config; + /// Initializes a lokinet instance by initializing various objects and loading the configuration - /// (if {config_dir}/lokinet.ini exists). Does not actually start lokinet (call llarp_apple_start + /// (if /lokinet.ini exists). Does not actually start lokinet (call llarp_apple_start /// for that). /// /// Returns NULL if there was a problem initializing/loading the configuration, otherwise returns /// an opaque void pointer that should be passed into the other llarp_apple_* functions. /// - /// \param logger a logger callback that we pass log messages to to relay them (i.e. via NSLog). - /// - /// \param config_dir the lokinet configuration directory where lokinet.ini can be and the various - /// other lokinet state files go. - /// - /// \param default_bootstrap the path to the default bootstrap.signed included in installation, - /// which will be used if no explicit bootstrap is set in the config file. - /// - /// \param ip - char buffer where we will write the primary tunnel IP address as a string such as - /// "172.16.0.0". Will write up to 16 characters (including the null terminator). This will be - /// the tunnel IP from the lokinet.ini, if it exists and specifies a range, otherwise we'll - /// configure lokinet to use a currently-unused range and return that. - /// - /// \param netmask the tunnel netmask as a string such as "255.255.0.0". Will write up to 16 - /// characters (including the null terminator). - /// - /// \param dns the DNS address that should be configured to query lokinet, as a string such as - /// "172.16.0.1". Will write up to 16 characters (including the null terminator). + /// \param config pointer to a llarp_apple_config where we get the various settings needed + /// and return the ip/mask/dns fields needed for the tunnel. void* - llarp_apple_init( - ns_logger_callback ns_logger, - const char* config_dir, - const char* default_bootstrap, - char* ip, - char* netmask, - char* dns); + llarp_apple_init(llarp_apple_config* config); /// Starts the lokinet instance in a new thread. /// - /// \param packet_writer C function callback that will be called when we need to write a packet to - /// the packet tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, the size - /// of the data in bytes, and the opaque callback_context pointer. - /// - /// \param start_reading C function callback that will be called when lokinet is setup and ready - /// to start receiving packets from the packet tunnel. This should set up the read handler to - /// deliver packets via llarp_apple_incoming. This is called with a single argument of the opaque - /// callback_context pointer. + /// \param lokinet the void pointer returned by llarp_apple_init /// - /// \param callback_context Opaque pointer that is passed into the packet_writer and start_reading - /// callback, intended to allow context to be passed through to the callbacks. This code does - /// nothing with this pointer aside from passing it through to callbacks. + /// \param callback_context Opaque pointer that is passed into the various callbacks provided to + /// llarp_apple_init. This code does nothing with this pointer aside from passing it through to + /// callbacks. /// /// \returns 0 on succesful startup, -1 on failure. int - llarp_apple_start( - void* lokinet, - packet_writer_callback packet_writer, - start_reading_callback start_reading, - void* callback_context); + llarp_apple_start(void* lokinet, void* callback_context); /// 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 diff --git a/llarp/apple/route_manager.cpp b/llarp/apple/route_manager.cpp new file mode 100644 index 000000000..72310e953 --- /dev/null +++ b/llarp/apple/route_manager.cpp @@ -0,0 +1,61 @@ +#include "route_manager.hpp" + +namespace llarp::apple { + +void RouteManager::AddDefaultRouteViaInterface(std::string) +{ + LogWarn("AddDefaultRouteViaInterface with cbctx=", (bool) callback_context, ", adr=", (bool) route_callbacks.add_default_route); + if (callback_context and route_callbacks.add_default_route) + route_callbacks.add_default_route(callback_context); +} + +void RouteManager::DelDefaultRouteViaInterface(std::string) +{ + LogWarn("DelDefaultRouteViaInterface with cbctx=", (bool) callback_context, ", ddr=", (bool) route_callbacks.del_default_route); + if (callback_context and route_callbacks.del_default_route) + route_callbacks.del_default_route(callback_context); +} + +void +RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) +{ + LogWarn("AddRoute with cbctx=", (bool) callback_context, ", a4r=", (bool) route_callbacks.add_ipv4_route, + "a6r", (bool) route_callbacks.add_ipv6_route); + + if (callback_context) + { + if (range.IsV4()) { + if (route_callbacks.add_ipv4_route) + route_callbacks.add_ipv4_route( + range.BaseAddressString().c_str(), + net::TruncateV6(range.netmask_bits).ToString().c_str(), + callback_context); + } else { + if (route_callbacks.add_ipv6_route) + route_callbacks.add_ipv6_route(range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); + } + } +} + +void +RouteManager::DelRouteViaInterface(vpn::NetworkInterface&, IPRange range) +{ + LogWarn("DelRoute with cbctx=", (bool) callback_context, ", a4r=", (bool) route_callbacks.del_ipv4_route, + "a6r", (bool) route_callbacks.del_ipv6_route); + + if (callback_context) + { + if (range.IsV4()) { + if (route_callbacks.del_ipv4_route) + route_callbacks.del_ipv4_route( + range.BaseAddressString().c_str(), + net::TruncateV6(range.netmask_bits).ToString().c_str(), + callback_context); + } else { + if (route_callbacks.del_ipv6_route) + route_callbacks.del_ipv6_route(range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); + } + } +} + +} diff --git a/llarp/apple/route_manager.hpp b/llarp/apple/route_manager.hpp new file mode 100644 index 000000000..575408888 --- /dev/null +++ b/llarp/apple/route_manager.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include "context_wrapper.h" + +namespace llarp::apple { + +class RouteManager final : public llarp::vpn::IRouteManager { +public: + RouteManager(llarp_route_callbacks rcs, void* callback_context) + : route_callbacks{std::move(rcs)}, callback_context{callback_context} {} + + /// These are called for poking route holes, but we don't have to do that at all on macos + /// because the appex isn't subject to its own rules. + void + AddRoute(IPVariant_t ip, IPVariant_t gateway) override {} + + void + DelRoute(IPVariant_t ip, IPVariant_t gateway) override {} + + void + AddDefaultRouteViaInterface(std::string ifname) override; + + void + DelDefaultRouteViaInterface(std::string ifname) override; + + void + AddRouteViaInterface(vpn::NetworkInterface& vpn, IPRange range) override; + + void + DelRouteViaInterface(vpn::NetworkInterface& vpn, IPRange range) override; + + virtual std::vector + GetGatewaysNotOnInterface(std::string ifname) override { + // We can't get this on mac from our sandbox, but we don't actually need it because we + // ignore the gateway for AddRoute/DelRoute anyway, so just return a zero IP. + std::vector ret; + ret.push_back(huint32_t{0}); + return ret; + } + + void* callback_context = nullptr; + llarp_route_callbacks route_callbacks; +}; + +} diff --git a/llarp/apple/vpn_platform.hpp b/llarp/apple/vpn_platform.hpp index 72018b509..2f56974fd 100644 --- a/llarp/apple/vpn_platform.hpp +++ b/llarp/apple/vpn_platform.hpp @@ -2,6 +2,7 @@ #include #include "vpn_interface.hpp" +#include "route_manager.hpp" namespace llarp::apple { @@ -11,8 +12,11 @@ namespace llarp::apple explicit VPNPlatform( Context& ctx, VPNInterface::packet_write_callback packet_writer, - VPNInterface::on_readable_callback on_readable) + VPNInterface::on_readable_callback on_readable, + llarp_route_callbacks route_callbacks, + void* callback_context) : m_Context{ctx} + , m_RouteManager{std::move(route_callbacks), callback_context} , m_PacketWriter{std::move(packet_writer)} , m_OnReadable{std::move(on_readable)} {} @@ -22,8 +26,11 @@ namespace llarp::apple return std::make_shared(m_Context, m_PacketWriter, m_OnReadable); } + vpn::IRouteManager& RouteManager() override { return m_RouteManager; } + private: Context& m_Context; + apple::RouteManager m_RouteManager; VPNInterface::packet_write_callback m_PacketWriter; VPNInterface::on_readable_callback m_OnReadable; }; From fd759914b69d7320a3d848fb8db9d1791d6820f2 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Mon, 30 Aug 2021 17:25:06 -0300 Subject: [PATCH 22/45] Remove unused vars --- llarp/apple/PacketTunnelProvider.m | 4 ---- llarp/apple/context_wrapper.cpp | 1 - 2 files changed, 5 deletions(-) diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m index 56ef0ca22..26e35953c 100644 --- a/llarp/apple/PacketTunnelProvider.m +++ b/llarp/apple/PacketTunnelProvider.m @@ -154,10 +154,6 @@ void del_default_route(void* ctx) { - (void)startTunnelWithOptions:(NSDictionary*)options completionHandler:(void (^)(NSError*))completionHandler { - char ip_buf[16]; - char mask_buf[16]; - char dns_buf[16]; - NSString* default_bootstrap = [NSBundle.mainBundle pathForResource:@"bootstrap" ofType:@"signed"]; NSString* home = NSHomeDirectory(); diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index 2ede9a498..8d66911d0 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -57,7 +57,6 @@ llarp_apple_init(llarp_apple_config* appleconf) throw std::runtime_error{"Unexpected non-IPv4 tunnel range configured"}; std::strcpy(appleconf->tunnel_ipv4_ip, addr.c_str()); std::strcpy(appleconf->tunnel_ipv4_netmask, mask.c_str()); - // XXX possibly DNS needs to be the .0 instead of the .1 because mac reasons? std::strcpy(appleconf->tunnel_dns, addr.c_str()); // The default DNS bind setting just isn't something we can use as a non-root network extension From f00e78c1a3b0f551688a21aacfebac3a72287269 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 31 Aug 2021 20:15:48 -0300 Subject: [PATCH 23/45] Add DNS trampoline This runs a DNS listener on localhost:1053 that bounces requests to the upstream DNS through the tunnel. The idea here is that, when we turn on exit mode, we start libunbound bouncing the requests through the trampoline (since if it makes direct requests they won't go through the tunnel). (The actual libunbound configuration is still to follow). --- llarp/apple/CMakeLists.txt | 1 + llarp/apple/DNSTrampoline.h | 48 ++++++++++ llarp/apple/DNSTrampoline.m | 136 +++++++++++++++++++++++++++++ llarp/apple/PacketTunnelProvider.m | 49 ++++++++--- llarp/apple/context_wrapper.cpp | 21 ++++- llarp/apple/context_wrapper.h | 11 ++- 6 files changed, 250 insertions(+), 16 deletions(-) create mode 100644 llarp/apple/DNSTrampoline.h create mode 100644 llarp/apple/DNSTrampoline.m diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt index 69a356020..32c4f989b 100644 --- a/llarp/apple/CMakeLists.txt +++ b/llarp/apple/CMakeLists.txt @@ -19,6 +19,7 @@ target_sources(lokinet-platform PRIVATE vpn_interface.cpp route_manager.cpp cont add_executable(lokinet-extension MACOSX_BUNDLE PacketTunnelProvider.m + DNSTrampoline.m ) target_link_libraries(lokinet-extension PRIVATE liblokinet diff --git a/llarp/apple/DNSTrampoline.h b/llarp/apple/DNSTrampoline.h new file mode 100644 index 000000000..9e3446d76 --- /dev/null +++ b/llarp/apple/DNSTrampoline.h @@ -0,0 +1,48 @@ +#pragma once +#include +#include + +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. + * + * 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). + * 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. + * (This assumes a non-lokinet DNS; .loki and .snode get handled before either of these). + */ +@interface LLARPDNSTrampoline : NSObject +{ + // The socket libunbound talks with: + uv_udp_t request_socket; + // The reply address. This is a bit hacky: we configure libunbound to just use single address + // (rather than a range) so that we don't have to worry about tracking different reply addresses. + @public struct sockaddr reply_addr; + // UDP "session" aimed at the upstream DNS + @public NWUDPSession* upstream; + // Apple docs say writes could take time *and* the crappy Apple datagram write methods aren't + // callable again until the previous write finishes. Deal with this garbage API by queuing + // everything than using a uv_async to process the queue. + @public int write_ready; + @public NSMutableArray* pending_writes; + uv_async_t write_trigger; +} +- (void)startWithUpstreamDns:(NWUDPSession*) dns + listenPort:(uint16_t) listenPort + uvLoop:(uv_loop_t*) loop + completionHandler:(void (^)(NSError* error))completionHandler; + +- (void)flushWrites; + +- (void)dealloc; + +@end + diff --git a/llarp/apple/DNSTrampoline.m b/llarp/apple/DNSTrampoline.m new file mode 100644 index 000000000..b0aad0121 --- /dev/null +++ b/llarp/apple/DNSTrampoline.m @@ -0,0 +1,136 @@ +#include "DNSTrampoline.h" +#include + +NSString* error_domain = @"com.loki-project.lokinet"; + + +// Receiving an incoming packet, presumably from libunbound. NB: this is called from the libuv +// event loop. +static void on_request(uv_udp_t* socket, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) { + if (nread < 0) { + NSLog(@"Read error: %s", uv_strerror(nread)); + free(buf->base); + return; + } + + if (nread == 0 || !addr) { + if (buf) + free(buf->base); + return; + } + + LLARPDNSTrampoline* t = (__bridge LLARPDNSTrampoline*) socket->data; + + // We configure libunbound to use just one single port so we'll just send replies to the last port + // to talk to us. (And we're only listening on localhost in the first place). + t->reply_addr = *addr; + + // NSData takes care of calling free(buf->base) for us with this constructor: + [t->pending_writes addObject:[NSData dataWithBytesNoCopy:buf->base length:nread]]; + + [t flushWrites]; +} + +static void on_sent(uv_udp_send_t* req, int status) { + NSArray* datagrams = (__bridge_transfer NSArray*) req->data; + free(req); +} + +// NB: called from the libuv event loop (so we don't have to worry about the above and this one +// running at once from different threads). +static void write_flusher(uv_async_t* async) { + LLARPDNSTrampoline* t = (__bridge LLARPDNSTrampoline*) async->data; + if (t->pending_writes.count == 0) + return; + + NSArray* data = [NSArray arrayWithArray:t->pending_writes]; + [t->pending_writes removeAllObjects]; + __weak LLARPDNSTrampoline* weakSelf = t; + [t->upstream writeMultipleDatagrams:data completionHandler: ^(NSError* error) + { + if (error) + NSLog(@"Failed to send request to upstream DNS: %@", error); + + // Trigger another flush in case anything built up while Apple was doing its things. Just + // call it unconditionally (rather than checking the queue) because this handler is probably + // running in some other thread. + [weakSelf flushWrites]; + } + ]; +} + + +static void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { + buf->base = malloc(suggested_size); + buf->len = suggested_size; +} + +@implementation LLARPDNSTrampoline + +- (void)startWithUpstreamDns:(NWUDPSession*) dns + listenPort:(uint16_t) listenPort + uvLoop:(uv_loop_t*) loop + completionHandler:(void (^)(NSError* error))completionHandler +{ + pending_writes = [[NSMutableArray alloc] init]; + write_trigger.data = (__bridge void*) self; + uv_async_init(loop, &write_trigger, write_flusher); + + 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); + 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)]; + NSError *err = [NSError errorWithDomain:error_domain code:ret userInfo:@{@"Error": errstr}]; + NSLog(@"%@", err); + return completionHandler(err); + } + uv_udp_recv_start(&request_socket, alloc_buffer, on_request); + + NSLog(@"Starting DNS trampoline"); + + upstream = dns; + __weak LLARPDNSTrampoline* weakSelf = self; + [upstream setReadHandler: ^(NSArray* datagrams, NSError* error) { + // Reading a reply back from the UDP socket used to talk to upstream + if (error) { + NSLog(@"Reader handler failed: %@", error); + return; + } + LLARPDNSTrampoline* strongSelf = weakSelf; + if (!strongSelf || datagrams.count == 0) + return; + + uv_buf_t* buffers = malloc(datagrams.count * sizeof(uv_buf_t)); + size_t buf_count = 0; + for (NSData* packet in datagrams) { + buffers[buf_count].base = (void*) packet.bytes; + buffers[buf_count].len = packet.length; + buf_count++; + } + uv_udp_send_t* uvsend = malloc(sizeof(uv_udp_send_t)); + uvsend->data = (__bridge_retained void*) datagrams; + int ret = uv_udp_send(uvsend, &strongSelf->request_socket, buffers, buf_count, &strongSelf->reply_addr, on_sent); + free(buffers); + if (ret < 0) + NSLog(@"Error returning DNS responses to unbound: %s", uv_strerror(ret)); + } maxDatagrams:NSUIntegerMax]; + + completionHandler(nil); +} + +- (void)flushWrites +{ + uv_async_send(&write_trigger); +} + +- (void) dealloc +{ + NSLog(@"Shutting down DNS trampoline"); + uv_close((uv_handle_t*) &request_socket, NULL); + uv_close((uv_handle_t*) &write_trigger, NULL); +} + +@end diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m index 26e35953c..a8fcf2845 100644 --- a/llarp/apple/PacketTunnelProvider.m +++ b/llarp/apple/PacketTunnelProvider.m @@ -1,14 +1,18 @@ #include #include #include "context_wrapper.h" +#include "DNSTrampoline.h" -NSString* error_domain = @"com.loki-project.lokinet"; +// Port (on localhost) for our DNS trampoline for bouncing DNS requests through the exit route when +// in exit mode. +const uint16_t dns_trampoline_port = 1053; @interface LLARPPacketTunnel : NEPacketTunnelProvider { void* lokinet; @public NEPacketTunnelNetworkSettings* settings; @public NEIPv4Route* tun_route4; + LLARPDNSTrampoline* dns_tramp; } - (void)startTunnelWithOptions:(NSDictionary*)options @@ -26,9 +30,9 @@ NSString* error_domain = @"com.loki-project.lokinet"; @end -void nslogger(const char* msg) { NSLog(@"%s", msg); } +static void nslogger(const char* msg) { NSLog(@"%s", msg); } -void packet_writer(int af, const void* data, size_t size, void* ctx) { +static void packet_writer(int af, const void* data, size_t size, void* ctx) { if (ctx == nil || data == nil) return; @@ -38,7 +42,7 @@ void packet_writer(int af, const void* data, size_t size, void* ctx) { [t.packetFlow writePacketObjects:@[packet]]; } -void start_packet_reader(void* ctx) { +static void start_packet_reader(void* ctx) { if (ctx == nil) return; @@ -46,7 +50,7 @@ void start_packet_reader(void* ctx) { [t readPackets]; } -void add_ipv4_route(const char* addr, const char* netmask, void* ctx) { +static void add_ipv4_route(const char* addr, const char* netmask, void* ctx) { NEIPv4Route* route = [[NEIPv4Route alloc] initWithDestinationAddress: [NSString stringWithUTF8String:addr] subnetMask: [NSString stringWithUTF8String:netmask]]; @@ -63,7 +67,7 @@ void add_ipv4_route(const char* addr, const char* netmask, void* ctx) { [t updateNetworkSettings]; } -void del_ipv4_route(const char* addr, const char* netmask, void* ctx) { +static void del_ipv4_route(const char* addr, const char* netmask, void* ctx) { NEIPv4Route* route = [[NEIPv4Route alloc] initWithDestinationAddress: [NSString stringWithUTF8String:addr] subnetMask: [NSString stringWithUTF8String:netmask]]; @@ -84,7 +88,7 @@ void del_ipv4_route(const char* addr, const char* netmask, void* ctx) { } } -void add_ipv6_route(const char* addr, int prefix, void* ctx) { +static void add_ipv6_route(const char* addr, int prefix, void* ctx) { NEIPv6Route* route = [[NEIPv6Route alloc] initWithDestinationAddress: [NSString stringWithUTF8String:addr] networkPrefixLength: [NSNumber numberWithInt:prefix]]; @@ -100,7 +104,8 @@ void add_ipv6_route(const char* addr, int prefix, void* ctx) { [t updateNetworkSettings]; } -void del_ipv6_route(const char* addr, int prefix, void* ctx) { + +static void del_ipv6_route(const char* addr, int prefix, void* ctx) { NEIPv6Route* route = [[NEIPv6Route alloc] initWithDestinationAddress: [NSString stringWithUTF8String:addr] networkPrefixLength: [NSNumber numberWithInt:prefix]]; @@ -120,7 +125,8 @@ void del_ipv6_route(const char* addr, int prefix, void* ctx) { [t updateNetworkSettings]; } } -void add_default_route(void* ctx) { + +static void add_default_route(void* ctx) { LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; t->settings.IPv4Settings.includedRoutes = @[NEIPv4Route.defaultRoute]; @@ -128,7 +134,8 @@ void add_default_route(void* ctx) { [t updateNetworkSettings]; } -void del_default_route(void* ctx) { + +static void del_default_route(void* ctx) { LLARPPacketTunnel* t = (__bridge LLARPPacketTunnel*) ctx; t->settings.IPv4Settings.includedRoutes = @[t->tun_route4]; @@ -182,13 +189,13 @@ void del_default_route(void* ctx) { NSString* ip = [NSString stringWithUTF8String:conf.tunnel_ipv4_ip]; NSString* mask = [NSString stringWithUTF8String:conf.tunnel_ipv4_netmask]; - NSString* dnsaddr = [NSString stringWithUTF8String:conf.tunnel_dns]; // 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:@[dnsaddr]]; + NEDNSSettings* dns = [[NEDNSSettings alloc] initWithServers:@[ip]]; dns.domainName = @"localhost.loki"; + dns.matchDomains = @[@""]; // In theory, matchDomains is supposed to be set to DNS suffixes that we resolve. This seems // highly unreliable, though: often it just doesn't work at all (perhaps only if we make ourselves // the default route?), and even when it does work, it seems there are secret reasons that some @@ -203,6 +210,11 @@ void del_default_route(void* ctx) { dns.matchDomains = @[@""]; dns.matchDomainsNoSearch = true; dns.searchDomains = @[]; + + NWHostEndpoint* upstreamdns_ep; + if (strlen(conf.upstream_dns)) + upstreamdns_ep = [NWHostEndpoint endpointWithHostname:[NSString stringWithUTF8String:conf.upstream_dns] port:@(conf.upstream_dns_port).stringValue]; + NEIPv4Settings* ipv4 = [[NEIPv4Settings alloc] initWithAddresses:@[ip] subnetMasks:@[mask]]; tun_route4 = [[NEIPv4Route alloc] initWithDestinationAddress:ip subnetMask: mask]; @@ -226,7 +238,18 @@ void del_default_route(void* ctx) { lokinet = nil; return completionHandler(start_failure); } - completionHandler(nil); + + NWUDPSession* upstreamdns = [strongSelf createUDPSessionThroughTunnelToEndpoint:upstreamdns_ep fromEndpoint:nil]; + strongSelf->dns_tramp = [LLARPDNSTrampoline alloc]; + [strongSelf->dns_tramp + startWithUpstreamDns:upstreamdns + listenPort:dns_trampoline_port + uvLoop:llarp_apple_get_uv_loop(strongSelf->lokinet) + completionHandler:^(NSError* error) { + if (error) + NSLog(@"Error starting dns trampoline: %@", error); + return completionHandler(error); + }]; }]; } diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index 8d66911d0..84d98e67c 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -1,9 +1,11 @@ #include #include +#include #include #include #include #include +#include #include "vpn_interface.hpp" #include "context_wrapper.h" #include "context.hpp" @@ -57,7 +59,15 @@ llarp_apple_init(llarp_apple_config* appleconf) throw std::runtime_error{"Unexpected non-IPv4 tunnel range configured"}; std::strcpy(appleconf->tunnel_ipv4_ip, addr.c_str()); std::strcpy(appleconf->tunnel_ipv4_netmask, mask.c_str()); - std::strcpy(appleconf->tunnel_dns, addr.c_str()); + + appleconf->upstream_dns[0] = '\0'; + for (auto& upstream : config->dns.m_upstreamDNS) { + if (upstream.isIPv4()) { + std::strcpy(appleconf->upstream_dns, upstream.hostString().c_str()); + appleconf->upstream_dns_port = upstream.getPort(); + break; + } + } // 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. @@ -135,6 +145,15 @@ llarp_apple_start( return 0; } +uv_loop_t* +llarp_apple_get_uv_loop(void* lokinet) +{ + auto& inst = *static_cast(lokinet); + auto uvw = inst.context.loop->MaybeGetUVWLoop(); + assert(uvw); + return uvw->raw(); +} + int llarp_apple_incoming(void* lokinet, const void* bytes, size_t size) { diff --git a/llarp/apple/context_wrapper.h b/llarp/apple/context_wrapper.h index 279dd7cf1..425986015 100644 --- a/llarp/apple/context_wrapper.h +++ b/llarp/apple/context_wrapper.h @@ -10,6 +10,7 @@ extern "C" #include #include +#include /// C callback function for us to invoke when we need to write a packet typedef void(*packet_writer_callback)(int af, const void* data, size_t size, void* ctx); @@ -66,8 +67,10 @@ extern "C" char tunnel_ipv4_ip[16]; /// llarp_apple_init writes the netmask of the tunnel address here, null-terminated. char tunnel_ipv4_netmask[16]; - /// The DNS server IPv4 address the OS should use. Null-terminated. - char tunnel_dns[16]; + /// The first upstream DNS server's IPv4 address the OS should use when in exit mode. + /// (Currently on mac in exit mode we only support querying the first such configured server). + char upstream_dns[16]; + uint16_t upstream_dns_port; /// \defgroup callbacks Callbacks /// Callbacks we invoke for various operations that require glue into the Apple network @@ -119,6 +122,10 @@ extern "C" int llarp_apple_start(void* lokinet, void* callback_context); + /// Returns a pointer to the uv event loop. Must have called llarp_apple_start already. + 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 From 0f097450d74d296252cfd7c09f7a58aed885dfa3 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Tue, 31 Aug 2021 21:15:20 -0300 Subject: [PATCH 24/45] Remove debug --- llarp/apple/route_manager.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/llarp/apple/route_manager.cpp b/llarp/apple/route_manager.cpp index 72310e953..9ec9253e2 100644 --- a/llarp/apple/route_manager.cpp +++ b/llarp/apple/route_manager.cpp @@ -4,14 +4,12 @@ namespace llarp::apple { void RouteManager::AddDefaultRouteViaInterface(std::string) { - LogWarn("AddDefaultRouteViaInterface with cbctx=", (bool) callback_context, ", adr=", (bool) route_callbacks.add_default_route); if (callback_context and route_callbacks.add_default_route) route_callbacks.add_default_route(callback_context); } void RouteManager::DelDefaultRouteViaInterface(std::string) { - LogWarn("DelDefaultRouteViaInterface with cbctx=", (bool) callback_context, ", ddr=", (bool) route_callbacks.del_default_route); if (callback_context and route_callbacks.del_default_route) route_callbacks.del_default_route(callback_context); } @@ -19,9 +17,6 @@ void RouteManager::DelDefaultRouteViaInterface(std::string) void RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) { - LogWarn("AddRoute with cbctx=", (bool) callback_context, ", a4r=", (bool) route_callbacks.add_ipv4_route, - "a6r", (bool) route_callbacks.add_ipv6_route); - if (callback_context) { if (range.IsV4()) { @@ -40,9 +35,6 @@ RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) void RouteManager::DelRouteViaInterface(vpn::NetworkInterface&, IPRange range) { - LogWarn("DelRoute with cbctx=", (bool) callback_context, ", a4r=", (bool) route_callbacks.del_ipv4_route, - "a6r", (bool) route_callbacks.del_ipv6_route); - if (callback_context) { if (range.IsV4()) { From 9dd604820f8e0859528902e7f50c28df83ea7c44 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 15:10:08 -0300 Subject: [PATCH 25/45] Unleak exit mode DNS via unbound DNS trampoline on (macOS) When we enable/disable exit mode on this restarts the unbound DNS responder with the DNS trampoline (or restores upstream, when disabling) to properly route DNS requests through the tunnel (because libunbound's direct requests don't get tunneled because unbound is inside the network extension). --- llarp/apple/CMakeLists.txt | 2 +- llarp/apple/DNSTrampoline.m | 2 +- llarp/apple/PacketTunnelProvider.m | 5 +---- llarp/apple/context_wrapper.cpp | 2 ++ llarp/apple/context_wrapper.h | 4 ++++ llarp/apple/route_manager.cpp | 36 ++++++++++++++++++++++++++++++ llarp/apple/route_manager.hpp | 12 ++++++++-- llarp/apple/vpn_platform.cpp | 22 ++++++++++++++++++ llarp/apple/vpn_platform.hpp | 12 ++-------- llarp/dns/server.cpp | 13 ++++++----- llarp/dns/server.hpp | 4 ++++ llarp/dns/unbound_resolver.cpp | 21 ++++++++++++++++- llarp/handlers/tun.cpp | 29 ++++++++++++++++++++++-- llarp/handlers/tun.hpp | 5 +++++ llarp/service/endpoint.hpp | 1 - 15 files changed, 142 insertions(+), 28 deletions(-) create mode 100644 llarp/apple/vpn_platform.cpp diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt index 32c4f989b..a2799167e 100644 --- a/llarp/apple/CMakeLists.txt +++ b/llarp/apple/CMakeLists.txt @@ -15,7 +15,7 @@ find_library(COREFOUNDATION CoreFoundation REQUIRED) target_sources(lokinet-util PRIVATE apple_logger.cpp) target_link_libraries(lokinet-util PUBLIC ${FOUNDATION}) -target_sources(lokinet-platform PRIVATE vpn_interface.cpp route_manager.cpp context_wrapper.cpp) +target_sources(lokinet-platform PRIVATE vpn_platform.cpp vpn_interface.cpp route_manager.cpp context_wrapper.cpp) add_executable(lokinet-extension MACOSX_BUNDLE PacketTunnelProvider.m diff --git a/llarp/apple/DNSTrampoline.m b/llarp/apple/DNSTrampoline.m index b0aad0121..0a78a13e2 100644 --- a/llarp/apple/DNSTrampoline.m +++ b/llarp/apple/DNSTrampoline.m @@ -128,7 +128,7 @@ static void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* b - (void) dealloc { - NSLog(@"Shutting down DNS trampoline"); + NSLog(@"Stopping DNS trampoline"); uv_close((uv_handle_t*) &request_socket, NULL); uv_close((uv_handle_t*) &write_trigger, NULL); } diff --git a/llarp/apple/PacketTunnelProvider.m b/llarp/apple/PacketTunnelProvider.m index a8fcf2845..7e03d5693 100644 --- a/llarp/apple/PacketTunnelProvider.m +++ b/llarp/apple/PacketTunnelProvider.m @@ -3,10 +3,6 @@ #include "context_wrapper.h" #include "DNSTrampoline.h" -// Port (on localhost) for our DNS trampoline for bouncing DNS requests through the exit route when -// in exit mode. -const uint16_t dns_trampoline_port = 1053; - @interface LLARPPacketTunnel : NEPacketTunnelProvider { void* lokinet; @@ -239,6 +235,7 @@ 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); NWUDPSession* upstreamdns = [strongSelf createUDPSessionThroughTunnelToEndpoint:upstreamdns_ep fromEndpoint:nil]; strongSelf->dns_tramp = [LLARPDNSTrampoline alloc]; [strongSelf->dns_tramp diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index 84d98e67c..6d6cbd0c8 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -29,6 +29,8 @@ namespace } // namespace +const uint16_t dns_trampoline_port = 1053; + void* llarp_apple_init(llarp_apple_config* appleconf) { diff --git a/llarp/apple/context_wrapper.h b/llarp/apple/context_wrapper.h index 425986015..74ac38eed 100644 --- a/llarp/apple/context_wrapper.h +++ b/llarp/apple/context_wrapper.h @@ -12,6 +12,10 @@ extern "C" #include #include + // Port (on localhost) for our DNS trampoline for bouncing DNS requests through the exit route + // when in exit mode. + extern const uint16_t dns_trampoline_port; + /// C callback function for us to invoke when we need to write a packet typedef void(*packet_writer_callback)(int af, const void* data, size_t size, void* ctx); diff --git a/llarp/apple/route_manager.cpp b/llarp/apple/route_manager.cpp index 9ec9253e2..87376f576 100644 --- a/llarp/apple/route_manager.cpp +++ b/llarp/apple/route_manager.cpp @@ -1,15 +1,49 @@ #include "route_manager.hpp" +#include +#include +#include +#include namespace llarp::apple { +void RouteManager::check_trampoline(bool enable) { + if (trampoline_active == enable) + return; + auto router = context.router; + if (!router) { + LogError("Cannot reconfigure to use DNS trampoline: no router"); + return; + } + + std::shared_ptr tun; + router->hiddenServiceContext().ForEachService([&tun] (const auto& name, const auto ep) { + tun = std::dynamic_pointer_cast(ep); + return !tun; + }); + + if (!tun) { + LogError("Cannot reconfigure to use DNS trampoline: no tun endpoint found (!?)"); + return; + } + + if (enable) + saved_upstream_dns = tun->ReconfigureDNS({SockAddr{127, 0, 0, 1, huint16_t{dns_trampoline_port}}}); + else + tun->ReconfigureDNS(std::move(saved_upstream_dns)); + trampoline_active = enable; +} + + void RouteManager::AddDefaultRouteViaInterface(std::string) { + check_trampoline(true); if (callback_context and route_callbacks.add_default_route) route_callbacks.add_default_route(callback_context); } void RouteManager::DelDefaultRouteViaInterface(std::string) { + check_trampoline(false); if (callback_context and route_callbacks.del_default_route) route_callbacks.del_default_route(callback_context); } @@ -17,6 +51,7 @@ void RouteManager::DelDefaultRouteViaInterface(std::string) void RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) { + check_trampoline(true); if (callback_context) { if (range.IsV4()) { @@ -35,6 +70,7 @@ RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) void RouteManager::DelRouteViaInterface(vpn::NetworkInterface&, IPRange range) { + check_trampoline(false); if (callback_context) { if (range.IsV4()) { diff --git a/llarp/apple/route_manager.hpp b/llarp/apple/route_manager.hpp index 575408888..e012c3dc0 100644 --- a/llarp/apple/route_manager.hpp +++ b/llarp/apple/route_manager.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include "context_wrapper.h" @@ -7,8 +8,8 @@ namespace llarp::apple { class RouteManager final : public llarp::vpn::IRouteManager { public: - RouteManager(llarp_route_callbacks rcs, void* callback_context) - : route_callbacks{std::move(rcs)}, callback_context{callback_context} {} + RouteManager(llarp::Context& ctx, llarp_route_callbacks rcs, void* callback_context) + : context{ctx}, route_callbacks{std::move(rcs)}, callback_context{callback_context} {} /// These are called for poking route holes, but we don't have to do that at all on macos /// because the appex isn't subject to its own rules. @@ -39,6 +40,13 @@ public: return ret; } +private: + + llarp::Context& context; + bool trampoline_active = false; + std::vector saved_upstream_dns; + void check_trampoline(bool enable); + void* callback_context = nullptr; llarp_route_callbacks route_callbacks; }; diff --git a/llarp/apple/vpn_platform.cpp b/llarp/apple/vpn_platform.cpp new file mode 100644 index 000000000..b11c0b05b --- /dev/null +++ b/llarp/apple/vpn_platform.cpp @@ -0,0 +1,22 @@ +#include "vpn_platform.hpp" +#include "context.hpp" + +namespace llarp::apple +{ + VPNPlatform::VPNPlatform( + Context& ctx, + VPNInterface::packet_write_callback packet_writer, + VPNInterface::on_readable_callback on_readable, + llarp_route_callbacks route_callbacks, + void* callback_context) + : m_Context{ctx} + , m_RouteManager{ctx, std::move(route_callbacks), callback_context} + , m_PacketWriter{std::move(packet_writer)} + , m_OnReadable{std::move(on_readable)} + {} + + std::shared_ptr VPNPlatform::ObtainInterface(vpn::InterfaceInfo) + { + return std::make_shared(m_Context, m_PacketWriter, m_OnReadable); + } +} // namespace llarp::apple diff --git a/llarp/apple/vpn_platform.hpp b/llarp/apple/vpn_platform.hpp index 2f56974fd..974a79305 100644 --- a/llarp/apple/vpn_platform.hpp +++ b/llarp/apple/vpn_platform.hpp @@ -14,17 +14,9 @@ namespace llarp::apple VPNInterface::packet_write_callback packet_writer, VPNInterface::on_readable_callback on_readable, llarp_route_callbacks route_callbacks, - void* callback_context) - : m_Context{ctx} - , m_RouteManager{std::move(route_callbacks), callback_context} - , m_PacketWriter{std::move(packet_writer)} - , m_OnReadable{std::move(on_readable)} - {} + void* callback_context); - std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override - { - return std::make_shared(m_Context, m_PacketWriter, m_OnReadable); - } + std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override; vpn::IRouteManager& RouteManager() override { return m_RouteManager; } diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index 5c8d6b4ca..e22a51db2 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -70,6 +70,7 @@ namespace llarp::dns m_UnboundResolver = std::make_shared(m_Loop, std::move(replyFunc), std::move(failFunc)); + m_Resolvers.clear(); if (not m_UnboundResolver->Init()) { llarp::LogError("Failed to initialize upstream DNS resolver."); @@ -102,9 +103,13 @@ namespace llarp::dns llarp::LogError("dns reply failed"); } + bool PacketHandler::IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const { + return m_Resolvers.count(to); + } + bool PacketHandler::ShouldHandlePacket( - const SockAddr& to, [[maybe_unused]] const SockAddr& from, llarp_buffer_t buf) const + const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) const { MessageHeader hdr; if (not hdr.Decode(&buf)) @@ -121,11 +126,7 @@ namespace llarp::dns if (m_QueryHandler and m_QueryHandler->ShouldHookDNSMessage(msg)) return true; - if (m_Resolvers.find(to) != m_Resolvers.end()) - { - return false; - } - return true; + return !IsUpstreamResolver(to, from); } void diff --git a/llarp/dns/server.hpp b/llarp/dns/server.hpp index 21f45ed54..2242ba450 100644 --- a/llarp/dns/server.hpp +++ b/llarp/dns/server.hpp @@ -56,6 +56,10 @@ namespace llarp virtual void SendServerMessageBufferTo(const SockAddr& to, const SockAddr& from, llarp_buffer_t buf) = 0; + // Returns true if this packet is something that looks like it's going to an upstream + // resolver, i.e. matches a configured resolver. + virtual bool IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const; + private: void HandleUpstreamFailure(const SockAddr& from, const SockAddr& to, Message msg); diff --git a/llarp/dns/unbound_resolver.cpp b/llarp/dns/unbound_resolver.cpp index a6e747523..9df195095 100644 --- a/llarp/dns/unbound_resolver.cpp +++ b/llarp/dns/unbound_resolver.cpp @@ -140,7 +140,8 @@ namespace llarp::dns UnboundResolver::AddUpstreamResolver(const SockAddr& upstreamResolver) { std::stringstream ss; - ss << upstreamResolver.hostString(); + auto hoststr = upstreamResolver.hostString(); + ss << hoststr; if (const auto port = upstreamResolver.getPort(); port != 53) ss << "@" << port; @@ -151,6 +152,24 @@ namespace llarp::dns 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") { + // 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()); + + // 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"); + } +#endif + return true; } diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 8da523b22..f0a754cf4 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -35,8 +35,8 @@ namespace llarp namespace handlers { // Intercepts DNS IP packets going to an IP on the tun interface; this is currently used on - // Android where binding to a DNS port (i.e. via llarp::dns::Proxy) isn't possible because of OS - // restrictions, but a tun interface *is* available. + // Android and macOS where binding to a DNS port (i.e. via llarp::dns::Proxy) isn't possible + // because of OS restrictions, but a tun interface *is* available. class DnsInterceptor : public dns::PacketHandler { public: @@ -61,6 +61,20 @@ namespace llarp m_Endpoint->HandleWriteIPPacket( pkt.ConstBuffer(), net::ExpandV4(from.asIPv4()), net::ExpandV4(to.asIPv4()), 0); } + +#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. + bool + IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const override + { + LogError("IsUpstreamResolver? ", to.asIPv6(), " != ", m_Endpoint->GetIfAddr(), ", from=", from); + return to.asIPv6() != m_Endpoint->GetIfAddr(); + } +#endif }; TunEndpoint::TunEndpoint(AbstractRouter* r, service::Context* parent) @@ -136,6 +150,17 @@ namespace llarp m_Resolver->Restart(); } + std::vector + TunEndpoint::ReconfigureDNS(std::vector servers) + { + std::swap(m_UpstreamResolvers, servers); + m_Resolver->Stop(); + if (!m_Resolver->Start( + m_LocalResolverAddr.createSockAddr(), m_UpstreamResolvers, m_hostfiles)) + llarp::LogError(Name(), " failed to reconfigure DNS server"); + return servers; + } + bool TunEndpoint::Configure(const NetworkConfig& conf, const DnsConfig& dnsConf) { diff --git a/llarp/handlers/tun.hpp b/llarp/handlers/tun.hpp index 4be9ba909..6ea44b794 100644 --- a/llarp/handlers/tun.hpp +++ b/llarp/handlers/tun.hpp @@ -43,6 +43,11 @@ namespace llarp void Thaw() override; + // Reconfigures DNS servers and restarts libunbound with the new servers. Returns the old set + // of configured dns servers. + std::vector + ReconfigureDNS(std::vector servers); + bool Configure(const NetworkConfig& conf, const DnsConfig& dnsConf) override; diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index 0fd8c625c..cfb5a2ef9 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -11,7 +11,6 @@ #include "identity.hpp" #include "pendingbuffer.hpp" #include "protocol.hpp" -#include "quic/server.hpp" #include "sendcontext.hpp" #include "service/protocol_type.hpp" #include "session.hpp" From e11efe9bc5413d9ec4202579926fa54044843c96 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 15:31:45 -0300 Subject: [PATCH 26/45] Reformat --- llarp/apple/DNSTrampoline.h | 19 +++-- llarp/apple/context.hpp | 3 +- llarp/apple/context_wrapper.cpp | 32 ++++--- llarp/apple/context_wrapper.h | 144 ++++++++++++++++---------------- llarp/apple/route_manager.cpp | 142 +++++++++++++++++-------------- llarp/apple/route_manager.hpp | 41 +++++---- llarp/apple/vpn_platform.hpp | 6 +- llarp/dns/server.cpp | 4 +- llarp/dns/server.hpp | 3 +- llarp/dns/unbound_resolver.cpp | 21 ++--- llarp/handlers/tun.cpp | 17 ++-- 11 files changed, 230 insertions(+), 202 deletions(-) diff --git a/llarp/apple/DNSTrampoline.h b/llarp/apple/DNSTrampoline.h index 9e3446d76..4935d43c8 100644 --- a/llarp/apple/DNSTrampoline.h +++ b/llarp/apple/DNSTrampoline.h @@ -25,19 +25,23 @@ extern NSString* error_domain; uv_udp_t request_socket; // The reply address. This is a bit hacky: we configure libunbound to just use single address // (rather than a range) so that we don't have to worry about tracking different reply addresses. - @public struct sockaddr reply_addr; + @public + struct sockaddr reply_addr; // UDP "session" aimed at the upstream DNS - @public NWUDPSession* upstream; + @public + NWUDPSession* upstream; // Apple docs say writes could take time *and* the crappy Apple datagram write methods aren't // callable again until the previous write finishes. Deal with this garbage API by queuing // everything than using a uv_async to process the queue. - @public int write_ready; - @public NSMutableArray* pending_writes; + @public + int write_ready; + @public + NSMutableArray* pending_writes; uv_async_t write_trigger; } -- (void)startWithUpstreamDns:(NWUDPSession*) dns - listenPort:(uint16_t) listenPort - uvLoop:(uv_loop_t*) loop +- (void)startWithUpstreamDns:(NWUDPSession*)dns + listenPort:(uint16_t)listenPort + uvLoop:(uv_loop_t*)loop completionHandler:(void (^)(NSError* error))completionHandler; - (void)flushWrites; @@ -45,4 +49,3 @@ extern NSString* error_domain; - (void)dealloc; @end - diff --git a/llarp/apple/context.hpp b/llarp/apple/context.hpp index a3b92ad75..4fc808874 100644 --- a/llarp/apple/context.hpp +++ b/llarp/apple/context.hpp @@ -11,7 +11,8 @@ namespace llarp::apple std::shared_ptr makeVPNPlatform() override { - return std::make_shared(*this, m_PacketWriter, m_OnReadable, route_callbacks, callback_context); + return std::make_shared( + *this, m_PacketWriter, m_OnReadable, route_callbacks, callback_context); } // Callbacks that must be set for packet handling *before* calling Setup/Configure/Run; the main diff --git a/llarp/apple/context_wrapper.cpp b/llarp/apple/context_wrapper.cpp index 6d6cbd0c8..ce9354540 100644 --- a/llarp/apple/context_wrapper.cpp +++ b/llarp/apple/context_wrapper.cpp @@ -34,7 +34,8 @@ const uint16_t dns_trampoline_port = 1053; void* llarp_apple_init(llarp_apple_config* appleconf) { - llarp::LogContext::Instance().logStream = std::make_unique(appleconf->ns_logger); + llarp::LogContext::Instance().logStream = + std::make_unique(appleconf->ns_logger); try { @@ -42,7 +43,7 @@ llarp_apple_init(llarp_apple_config* appleconf) auto config = std::make_shared(config_dir); fs::path config_path = config_dir / "lokinet.ini"; if (!fs::exists(config_path)) - llarp::ensureConfig(config_dir, config_path, /*overwrite=*/ false, /*router=*/ false); + llarp::ensureConfig(config_dir, config_path, /*overwrite=*/false, /*router=*/false); config->Load(config_path); // If no range is specified then go look for a free one, set that in the config, and then return @@ -63,8 +64,10 @@ llarp_apple_init(llarp_apple_config* appleconf) std::strcpy(appleconf->tunnel_ipv4_netmask, mask.c_str()); appleconf->upstream_dns[0] = '\0'; - for (auto& upstream : config->dns.m_upstreamDNS) { - if (upstream.isIPv4()) { + for (auto& upstream : config->dns.m_upstreamDNS) + { + if (upstream.isIPv4()) + { std::strcpy(appleconf->upstream_dns, upstream.hostString().c_str()); appleconf->upstream_dns_port = upstream.getPort(); break; @@ -87,7 +90,6 @@ llarp_apple_init(llarp_apple_config* appleconf) inst->packet_writer = appleconf->packet_writer; inst->start_reading = appleconf->start_reading; - return inst.release(); } catch (const std::exception& e) @@ -98,25 +100,21 @@ llarp_apple_init(llarp_apple_config* appleconf) } int -llarp_apple_start( - void* lokinet, - void* callback_context) +llarp_apple_start(void* lokinet, void* callback_context) { auto* inst = static_cast(lokinet); inst->context.callback_context = callback_context; - inst->context.m_PacketWriter = [inst, callback_context]( - int af_family, void* data, size_t size) { - inst->packet_writer(af_family, data, size, callback_context); - return true; + inst->context.m_PacketWriter = [inst, callback_context](int af_family, void* data, size_t size) { + inst->packet_writer(af_family, data, size, callback_context); + return true; }; - inst->context.m_OnReadable = - [inst, callback_context](llarp::apple::VPNInterface& iface) { - inst->iface = iface.weak_from_this(); - inst->start_reading(callback_context); - }; + inst->context.m_OnReadable = [inst, callback_context](llarp::apple::VPNInterface& iface) { + inst->iface = iface.weak_from_this(); + inst->start_reading(callback_context); + }; std::promise result; inst->runner = std::thread{[inst, &result] { diff --git a/llarp/apple/context_wrapper.h b/llarp/apple/context_wrapper.h index 74ac38eed..914446741 100644 --- a/llarp/apple/context_wrapper.h +++ b/llarp/apple/context_wrapper.h @@ -17,91 +17,91 @@ extern "C" extern const uint16_t dns_trampoline_port; /// C callback function for us to invoke when we need to write a packet - typedef void(*packet_writer_callback)(int af, const void* data, size_t size, void* ctx); + typedef void (*packet_writer_callback)(int af, const void* data, size_t size, void* ctx); /// C callback function to invoke once we are ready to start receiving packets - typedef void(*start_reading_callback)(void* ctx); + typedef void (*start_reading_callback)(void* ctx); /// C callback that bridges things into NSLog - typedef void(*ns_logger_callback)(const char* msg); + typedef void (*ns_logger_callback)(const char* msg); /// C callbacks to add/remove specific and default routes to the tunnel - typedef void(*llarp_route_ipv4_callback)(const char* addr, const char* netmask, void* ctx); - typedef void(*llarp_route_ipv6_callback)(const char* addr, int prefix, void* ctx); - typedef void(*llarp_default_route_callback)(void* ctx); - typedef struct llarp_route_callbacks { - /// Callback invoked to set up an IPv4 range that should be routed through the tunnel - /// interface. Called with the address and netmask. - llarp_route_ipv4_callback add_ipv4_route; - - /// Callback invoked to set the tunnel as the default IPv4 route. - llarp_default_route_callback add_ipv4_default_route; - - /// Callback invoked to remove a specific range from the tunnel IPv4 routes. Called with the - /// address and netmask. - llarp_route_ipv4_callback del_ipv4_route; - - /// Callback invoked to set up an IPv6 range that should be routed through the tunnel - /// interface. Called with the address and netmask. - llarp_route_ipv6_callback add_ipv6_route; - - /// Callback invoked to remove a specific range from the tunnel IPv6 routes. Called with the - /// address and netmask. - llarp_route_ipv6_callback del_ipv6_route; - - /// Callback invoked to set the tunnel as the default IPv4/IPv6 route. - llarp_default_route_callback add_default_route; - - /// Callback invoked to remove the tunnel as the default IPv4/IPv6 route. - llarp_default_route_callback del_default_route; + typedef void (*llarp_route_ipv4_callback)(const char* addr, const char* netmask, void* ctx); + typedef void (*llarp_route_ipv6_callback)(const char* addr, int prefix, void* ctx); + typedef void (*llarp_default_route_callback)(void* ctx); + typedef struct llarp_route_callbacks + { + /// Callback invoked to set up an IPv4 range that should be routed through the tunnel + /// interface. Called with the address and netmask. + llarp_route_ipv4_callback add_ipv4_route; + + /// Callback invoked to set the tunnel as the default IPv4 route. + llarp_default_route_callback add_ipv4_default_route; + + /// Callback invoked to remove a specific range from the tunnel IPv4 routes. Called with the + /// address and netmask. + llarp_route_ipv4_callback del_ipv4_route; + + /// Callback invoked to set up an IPv6 range that should be routed through the tunnel + /// interface. Called with the address and netmask. + llarp_route_ipv6_callback add_ipv6_route; + + /// Callback invoked to remove a specific range from the tunnel IPv6 routes. Called with the + /// address and netmask. + llarp_route_ipv6_callback del_ipv6_route; + + /// Callback invoked to set the tunnel as the default IPv4/IPv6 route. + llarp_default_route_callback add_default_route; + + /// Callback invoked to remove the tunnel as the default IPv4/IPv6 route. + llarp_default_route_callback del_default_route; } llarp_route_callbacks; /// Pack of crap to be passed into llarp_apple_init to initialize typedef struct llarp_apple_config { - /// lokinet configuration directory, expected to be the application-specific "home" directory, - /// which is where state files are stored and the lokinet.ini will be loaded (or created if it - /// doesn't exist). - const char* config_dir; - /// path to the default bootstrap.signed file included in installation, which will be used by - /// default when no specific bootstrap is in the config file. - const char* default_bootstrap; - /// llarp_apple_init writes the IP address for the primary tunnel IP address here, - /// null-terminated. - char tunnel_ipv4_ip[16]; - /// llarp_apple_init writes the netmask of the tunnel address here, null-terminated. - char tunnel_ipv4_netmask[16]; - /// The first upstream DNS server's IPv4 address the OS should use when in exit mode. - /// (Currently on mac in exit mode we only support querying the first such configured server). - char upstream_dns[16]; - uint16_t upstream_dns_port; - - /// \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 - /// llarp_apple_start when invoked. - /// @{ - - /// simple wrapper around NSLog for lokinet message logging - ns_logger_callback ns_logger; - - /// C function callback that will be called when we need to write a packet to the packet - /// tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, and the size of - /// the data in bytes. - packet_writer_callback packet_writer; - - /// C function callback that will be called when lokinet is setup and ready to start receiving - /// packets from the packet tunnel. This should set up the read handler to deliver packets - /// via llarp_apple_incoming. - start_reading_callback start_reading; - - /// Callbacks invoked to add/remove routes to the tunnel. - llarp_route_callbacks route_callbacks; - - /// @} + /// lokinet configuration directory, expected to be the application-specific "home" directory, + /// which is where state files are stored and the lokinet.ini will be loaded (or created if it + /// doesn't exist). + const char* config_dir; + /// path to the default bootstrap.signed file included in installation, which will be used by + /// default when no specific bootstrap is in the config file. + const char* default_bootstrap; + /// llarp_apple_init writes the IP address for the primary tunnel IP address here, + /// null-terminated. + char tunnel_ipv4_ip[16]; + /// llarp_apple_init writes the netmask of the tunnel address here, null-terminated. + char tunnel_ipv4_netmask[16]; + /// The first upstream DNS server's IPv4 address the OS should use when in exit mode. + /// (Currently on mac in exit mode we only support querying the first such configured server). + char upstream_dns[16]; + uint16_t upstream_dns_port; + + /// \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 + /// llarp_apple_start when invoked. + /// @{ + + /// simple wrapper around NSLog for lokinet message logging + ns_logger_callback ns_logger; + + /// C function callback that will be called when we need to write a packet to the packet + /// tunnel. Will be passed AF_INET or AF_INET6, a void pointer to the data, and the size of + /// the data in bytes. + packet_writer_callback packet_writer; + + /// C function callback that will be called when lokinet is setup and ready to start receiving + /// packets from the packet tunnel. This should set up the read handler to deliver packets + /// via llarp_apple_incoming. + start_reading_callback start_reading; + + /// Callbacks invoked to add/remove routes to the tunnel. + llarp_route_callbacks route_callbacks; + + /// @} } llarp_apple_config; - /// Initializes a lokinet instance by initializing various objects and loading the configuration /// (if /lokinet.ini exists). Does not actually start lokinet (call llarp_apple_start /// for that). diff --git a/llarp/apple/route_manager.cpp b/llarp/apple/route_manager.cpp index 87376f576..0bf170577 100644 --- a/llarp/apple/route_manager.cpp +++ b/llarp/apple/route_manager.cpp @@ -4,86 +4,98 @@ #include #include -namespace llarp::apple { - -void RouteManager::check_trampoline(bool enable) { - if (trampoline_active == enable) - return; - auto router = context.router; - if (!router) { - LogError("Cannot reconfigure to use DNS trampoline: no router"); - return; - } +namespace llarp::apple +{ + void + RouteManager::check_trampoline(bool enable) + { + if (trampoline_active == enable) + return; + auto router = context.router; + if (!router) + { + LogError("Cannot reconfigure to use DNS trampoline: no router"); + return; + } - std::shared_ptr tun; - router->hiddenServiceContext().ForEachService([&tun] (const auto& name, const auto ep) { + std::shared_ptr tun; + router->hiddenServiceContext().ForEachService([&tun](const auto& name, const auto ep) { tun = std::dynamic_pointer_cast(ep); return !tun; - }); + }); - if (!tun) { - LogError("Cannot reconfigure to use DNS trampoline: no tun endpoint found (!?)"); - return; - } - - if (enable) - saved_upstream_dns = tun->ReconfigureDNS({SockAddr{127, 0, 0, 1, huint16_t{dns_trampoline_port}}}); - else - tun->ReconfigureDNS(std::move(saved_upstream_dns)); - trampoline_active = enable; -} + if (!tun) + { + LogError("Cannot reconfigure to use DNS trampoline: no tun endpoint found (!?)"); + return; + } + if (enable) + saved_upstream_dns = + tun->ReconfigureDNS({SockAddr{127, 0, 0, 1, huint16_t{dns_trampoline_port}}}); + else + tun->ReconfigureDNS(std::move(saved_upstream_dns)); + trampoline_active = enable; + } -void RouteManager::AddDefaultRouteViaInterface(std::string) -{ - check_trampoline(true); + void RouteManager::AddDefaultRouteViaInterface(std::string) + { + check_trampoline(true); if (callback_context and route_callbacks.add_default_route) - route_callbacks.add_default_route(callback_context); -} + route_callbacks.add_default_route(callback_context); + } -void RouteManager::DelDefaultRouteViaInterface(std::string) -{ - check_trampoline(false); + void RouteManager::DelDefaultRouteViaInterface(std::string) + { + check_trampoline(false); if (callback_context and route_callbacks.del_default_route) - route_callbacks.del_default_route(callback_context); -} + route_callbacks.del_default_route(callback_context); + } -void -RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) -{ - check_trampoline(true); + void + RouteManager::AddRouteViaInterface(vpn::NetworkInterface&, IPRange range) + { + check_trampoline(true); if (callback_context) { - if (range.IsV4()) { - if (route_callbacks.add_ipv4_route) - route_callbacks.add_ipv4_route( - range.BaseAddressString().c_str(), - net::TruncateV6(range.netmask_bits).ToString().c_str(), - callback_context); - } else { - if (route_callbacks.add_ipv6_route) - route_callbacks.add_ipv6_route(range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); - } + if (range.IsV4()) + { + if (route_callbacks.add_ipv4_route) + route_callbacks.add_ipv4_route( + range.BaseAddressString().c_str(), + net::TruncateV6(range.netmask_bits).ToString().c_str(), + callback_context); + } + else + { + if (route_callbacks.add_ipv6_route) + route_callbacks.add_ipv6_route( + range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); + } } -} + } -void -RouteManager::DelRouteViaInterface(vpn::NetworkInterface&, IPRange range) -{ - check_trampoline(false); + void + RouteManager::DelRouteViaInterface(vpn::NetworkInterface&, IPRange range) + { + check_trampoline(false); if (callback_context) { - if (range.IsV4()) { - if (route_callbacks.del_ipv4_route) - route_callbacks.del_ipv4_route( - range.BaseAddressString().c_str(), - net::TruncateV6(range.netmask_bits).ToString().c_str(), - callback_context); - } else { - if (route_callbacks.del_ipv6_route) - route_callbacks.del_ipv6_route(range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); - } + if (range.IsV4()) + { + if (route_callbacks.del_ipv4_route) + route_callbacks.del_ipv4_route( + range.BaseAddressString().c_str(), + net::TruncateV6(range.netmask_bits).ToString().c_str(), + callback_context); + } + else + { + if (route_callbacks.del_ipv6_route) + route_callbacks.del_ipv6_route( + range.BaseAddressString().c_str(), range.HostmaskBits(), callback_context); + } } -} + } -} +} // namespace llarp::apple diff --git a/llarp/apple/route_manager.hpp b/llarp/apple/route_manager.hpp index e012c3dc0..cb8bb3f1b 100644 --- a/llarp/apple/route_manager.hpp +++ b/llarp/apple/route_manager.hpp @@ -4,20 +4,24 @@ #include #include "context_wrapper.h" -namespace llarp::apple { - -class RouteManager final : public llarp::vpn::IRouteManager { -public: +namespace llarp::apple +{ + class RouteManager final : public llarp::vpn::IRouteManager + { + public: RouteManager(llarp::Context& ctx, llarp_route_callbacks rcs, void* callback_context) - : context{ctx}, route_callbacks{std::move(rcs)}, callback_context{callback_context} {} + : context{ctx}, route_callbacks{std::move(rcs)}, callback_context{callback_context} + {} /// These are called for poking route holes, but we don't have to do that at all on macos /// because the appex isn't subject to its own rules. void - AddRoute(IPVariant_t ip, IPVariant_t gateway) override {} + AddRoute(IPVariant_t ip, IPVariant_t gateway) override + {} void - DelRoute(IPVariant_t ip, IPVariant_t gateway) override {} + DelRoute(IPVariant_t ip, IPVariant_t gateway) override + {} void AddDefaultRouteViaInterface(std::string ifname) override; @@ -32,23 +36,24 @@ public: DelRouteViaInterface(vpn::NetworkInterface& vpn, IPRange range) override; virtual std::vector - GetGatewaysNotOnInterface(std::string ifname) override { - // We can't get this on mac from our sandbox, but we don't actually need it because we - // ignore the gateway for AddRoute/DelRoute anyway, so just return a zero IP. - std::vector ret; - ret.push_back(huint32_t{0}); - return ret; + GetGatewaysNotOnInterface(std::string ifname) override + { + // We can't get this on mac from our sandbox, but we don't actually need it because we + // ignore the gateway for AddRoute/DelRoute anyway, so just return a zero IP. + std::vector ret; + ret.push_back(huint32_t{0}); + return ret; } -private: - + private: llarp::Context& context; bool trampoline_active = false; std::vector saved_upstream_dns; - void check_trampoline(bool enable); + void + check_trampoline(bool enable); void* callback_context = nullptr; llarp_route_callbacks route_callbacks; -}; + }; -} +} // namespace llarp::apple diff --git a/llarp/apple/vpn_platform.hpp b/llarp/apple/vpn_platform.hpp index 974a79305..04ce75646 100644 --- a/llarp/apple/vpn_platform.hpp +++ b/llarp/apple/vpn_platform.hpp @@ -18,7 +18,11 @@ namespace llarp::apple std::shared_ptr ObtainInterface(vpn::InterfaceInfo) override; - vpn::IRouteManager& RouteManager() override { return m_RouteManager; } + vpn::IRouteManager& + RouteManager() override + { + return m_RouteManager; + } private: Context& m_Context; diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index e22a51db2..d2cac921b 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -103,7 +103,9 @@ namespace llarp::dns llarp::LogError("dns reply failed"); } - bool PacketHandler::IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const { + bool + PacketHandler::IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const + { return m_Resolvers.count(to); } diff --git a/llarp/dns/server.hpp b/llarp/dns/server.hpp index 2242ba450..025ec8ef6 100644 --- a/llarp/dns/server.hpp +++ b/llarp/dns/server.hpp @@ -58,7 +58,8 @@ namespace llarp // Returns true if this packet is something that looks like it's going to an upstream // resolver, i.e. matches a configured resolver. - virtual bool IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const; + virtual bool + IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const; private: void diff --git a/llarp/dns/unbound_resolver.cpp b/llarp/dns/unbound_resolver.cpp index 9df195095..d115c3f52 100644 --- a/llarp/dns/unbound_resolver.cpp +++ b/llarp/dns/unbound_resolver.cpp @@ -157,16 +157,17 @@ namespace llarp::dns // 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") { - // 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()); - - // 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"); + if (hoststr == "127.0.0.1") + { + // 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()); + + // 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"); } #endif diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index f0a754cf4..61553acff 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -71,8 +71,9 @@ namespace llarp bool IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const override { - LogError("IsUpstreamResolver? ", to.asIPv6(), " != ", m_Endpoint->GetIfAddr(), ", from=", from); - return to.asIPv6() != m_Endpoint->GetIfAddr(); + LogError( + "IsUpstreamResolver? ", to.asIPv6(), " != ", m_Endpoint->GetIfAddr(), ", from=", from); + return to.asIPv6() != m_Endpoint->GetIfAddr(); } #endif }; @@ -153,12 +154,12 @@ namespace llarp std::vector TunEndpoint::ReconfigureDNS(std::vector servers) { - std::swap(m_UpstreamResolvers, servers); - m_Resolver->Stop(); - if (!m_Resolver->Start( - m_LocalResolverAddr.createSockAddr(), m_UpstreamResolvers, m_hostfiles)) - llarp::LogError(Name(), " failed to reconfigure DNS server"); - return servers; + std::swap(m_UpstreamResolvers, servers); + m_Resolver->Stop(); + if (!m_Resolver->Start( + m_LocalResolverAddr.createSockAddr(), m_UpstreamResolvers, m_hostfiles)) + llarp::LogError(Name(), " failed to reconfigure DNS server"); + return servers; } bool From a7decd5ec3e1855433682d9bb056d203a4da54e6 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 15:44:23 -0300 Subject: [PATCH 27/45] Silence warnings --- llarp/dns/server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index d2cac921b..7bf6b1e34 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -104,7 +104,7 @@ namespace llarp::dns } bool - PacketHandler::IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const + PacketHandler::IsUpstreamResolver(const SockAddr& to, [[maybe_unused]] const SockAddr& from) const { return m_Resolvers.count(to); } From 067fcf71d3457a598f9b3dd4ee6957ff53da88b0 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 16:00:37 -0300 Subject: [PATCH 28/45] Remove dead code --- daemon/lokinet.swift | 68 -------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/daemon/lokinet.swift b/daemon/lokinet.swift index 9ebf76940..69598e9d7 100644 --- a/daemon/lokinet.swift +++ b/daemon/lokinet.swift @@ -8,7 +8,6 @@ let app = NSApplication.shared class LokinetMain: NSObject, NSApplicationDelegate { var vpnManager = NETunnelProviderManager() let lokinetComponent = "com.loki-project.lokinet.network-extension" - var dnsComponent = "com.loki-project.lokinet.dns-proxy" func applicationDidFinishLaunching(_: Notification) { setupVPNJizz() @@ -18,63 +17,6 @@ class LokinetMain: NSObject, NSApplicationDelegate { app.terminate(self) } - func setupDNSJizz() { - NSLog("setting up dns settings") - let dns = NEDNSSettingsManager.shared() - let settings = NEDNSSettings(servers: ["172.16.0.1"]) - settings.matchDomains = ["*.loki", "*.snode"] - settings.matchDomainsNoSearch = true - settings.domainName = "localhost.loki" - dns.dnsSettings = settings - dns.loadFromPreferences { [self] (error: Error?) -> Void in - if let error = error { - NSLog(error.localizedDescription) - bail() - return - } - dns.saveToPreferences { [self] (error: Error?) -> Void in - if let error = error { - NSLog(error.localizedDescription) - bail() - return - } - NSLog("dns setting set up probably") - } - } - } - - func setupDNSProxyJizz() { - NSLog("setting up dns proxy") - let dns = NEDNSProxyManager.shared() - let provider = NEDNSProxyProviderProtocol() - provider.providerBundleIdentifier = dnsComponent - provider.username = "Anonymous" - provider.serverAddress = "loki.loki" - provider.includeAllNetworks = true - provider.enforceRoutes = true - dns.providerProtocol = provider - dns.localizedDescription = "lokinet dns" - dns.loadFromPreferences { [self] (error: Error?) -> Void in - if let error = error { - NSLog(error.localizedDescription) - bail() - return - } - provider.includeAllNetworks = true - provider.enforceRoutes = true - dns.isEnabled = true - dns.saveToPreferences { [self] (error: Error?) -> Void in - if let error = error { - NSLog(error.localizedDescription) - bail() - return - } - self.initDNSObserver() - NSLog("dns is up probably") - } - } - } - func setupVPNJizz() { NSLog("Starting up lokinet") NETunnelProviderManager.loadAllFromPreferences { [self] (savedManagers: [NETunnelProviderManager]?, error: Error?) in @@ -104,9 +46,6 @@ class LokinetMain: NSObject, NSApplicationDelegate { self.vpnManager.protocolConfiguration = providerProtocol self.vpnManager.isEnabled = true // self.vpnManager.isOnDemandEnabled = true - let rules = NEAppRule() - rules.matchDomains = ["*.snode", "*.loki"] - self.vpnManager.appRules = [rules] self.vpnManager.localizedDescription = "lokinet" self.vpnManager.saveToPreferences(completionHandler: { error -> Void in if error != nil { @@ -138,13 +77,6 @@ class LokinetMain: NSObject, NSApplicationDelegate { } } - func initDNSObserver() { - NotificationCenter.default.addObserver(forName: NSNotification.Name.NEDNSProxyConfigurationDidChange, object: NEDNSProxyManager.shared(), queue: OperationQueue.main) { _ -> Void in - let dns = NEDNSProxyManager.shared() - NSLog("%@", dns) - } - } - func initializeConnectionObserver() { NotificationCenter.default.addObserver(forName: NSNotification.Name.NEVPNStatusDidChange, object: vpnManager.connection, queue: OperationQueue.main) { _ -> Void in if self.vpnManager.connection.status == .invalid { From 1315dabcb974d08a7a12e71b0521f1577ef2e0d4 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 1 Sep 2021 16:28:11 -0400 Subject: [PATCH 29/45] disable language ASM, yolo --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index af550c638..e1bf223fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Has to be set before `project()`, and ignored on non-macos: set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "macOS deployment target (Apple clang only)") -set(LANGS ASM C CXX) +set(LANGS C CXX) if(APPLE) set(LANGS ${LANGS} OBJC Swift) endif() From f51d0a80a240115c0ffe1ad0a234b3810832afdd Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Wed, 1 Sep 2021 18:58:00 -0300 Subject: [PATCH 30/45] Forward-declare ub_ctx/ub_result Avoids needing unbound.h in the search path to include the unbound_resolver.hpp header. --- llarp/dns/unbound_resolver.cpp | 2 ++ llarp/dns/unbound_resolver.hpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/llarp/dns/unbound_resolver.cpp b/llarp/dns/unbound_resolver.cpp index d115c3f52..50c56f5fc 100644 --- a/llarp/dns/unbound_resolver.cpp +++ b/llarp/dns/unbound_resolver.cpp @@ -5,6 +5,8 @@ #include #include +#include + namespace llarp::dns { struct PendingUnboundLookup diff --git a/llarp/dns/unbound_resolver.hpp b/llarp/dns/unbound_resolver.hpp index 5c67c3ed4..4d79569ce 100644 --- a/llarp/dns/unbound_resolver.hpp +++ b/llarp/dns/unbound_resolver.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -17,6 +16,12 @@ #include #endif +extern "C" +{ + struct ub_ctx; + struct ub_result; +} + namespace llarp::dns { using ReplyFunction = From 10cd3318632e62ff3a0e1e787be8a787eaf7a1ae Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 2 Sep 2021 15:23:13 -0400 Subject: [PATCH 31/45] invert logic for android dns hook --- llarp/dns/server.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index 7bf6b1e34..c43b79671 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -127,8 +127,11 @@ namespace llarp::dns if (m_QueryHandler and m_QueryHandler->ShouldHookDNSMessage(msg)) return true; - +#ifdef ANDROID + return IsUpstreamResolver(to, from); +#else return !IsUpstreamResolver(to, from); +#endif } void From 8aef5d742d30634a5802347088d4051eda9af6c8 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 2 Sep 2021 19:07:40 -0300 Subject: [PATCH 32/45] Re-enable LTO; target macos 10.12+ --- CMakeLists.txt | 2 +- contrib/mac.sh | 2 +- daemon/CMakeLists.txt | 1 + llarp/apple/CMakeLists.txt | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1bf223fa..6b23ebe10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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.15 CACHE STRING "macOS deployment target (Apple clang only)") +set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12 CACHE STRING "macOS deployment target (Apple clang only)") set(LANGS C CXX) if(APPLE) diff --git a/contrib/mac.sh b/contrib/mac.sh index 548c9f8b2..4719b40d2 100755 --- a/contrib/mac.sh +++ b/contrib/mac.sh @@ -28,7 +28,7 @@ cmake \ -DWITH_SYSTEMD=OFF \ -DFORCE_OXENMQ_SUBMODULE=ON \ -DSUBMODULE_CHECK=OFF \ - -DWITH_LTO=OFF \ + -DWITH_LTO=ON \ -DCMAKE_BUILD_TYPE=Release \ "$@" \ .. diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index febc7314a..deb60ed0f 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -5,6 +5,7 @@ if(APPLE) add_executable(lokinet ${LOKINET_SWIFT_SOURCES}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Lokinet.modulemap.in ${CMAKE_CURRENT_BINARY_DIR}/swift/LokinetExtension/module.modulemap ESCAPE_QUOTES @ONLY) target_include_directories(lokinet PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/swift) + enable_lto(lokinet) else() add_executable(lokinet lokinet.cpp) add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) diff --git a/llarp/apple/CMakeLists.txt b/llarp/apple/CMakeLists.txt index a2799167e..58a54727a 100644 --- a/llarp/apple/CMakeLists.txt +++ b/llarp/apple/CMakeLists.txt @@ -21,6 +21,7 @@ add_executable(lokinet-extension MACOSX_BUNDLE PacketTunnelProvider.m DNSTrampoline.m ) +enable_lto(lokinet-extension) target_link_libraries(lokinet-extension PRIVATE liblokinet ${COREFOUNDATION} From 38335f13a28deac88c9ccd71a5d5ac0e1506938c Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 2 Sep 2021 19:09:02 -0300 Subject: [PATCH 33/45] Remove debugging --- llarp/handlers/tun.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 61553acff..fbc726cf0 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -71,8 +71,6 @@ namespace llarp bool IsUpstreamResolver(const SockAddr& to, const SockAddr& from) const override { - LogError( - "IsUpstreamResolver? ", to.asIPv6(), " != ", m_Endpoint->GetIfAddr(), ", from=", from); return to.asIPv6() != m_Endpoint->GetIfAddr(); } #endif From 92c7fb9872688a58096b3326519de3c8c21081af Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 2 Sep 2021 19:11:41 -0300 Subject: [PATCH 34/45] LOKINET_VERSION -> built in lokinet_VERSION --- CMakeLists.txt | 2 -- contrib/macos/Info.plist.in | 4 ++-- contrib/macos/LokinetExtension.Info.plist.in | 2 +- daemon/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b23ebe10..105ce499d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,8 +41,6 @@ if(RELEASE_MOTTO AND CMAKE_BUILD_TYPE MATCHES "[Rr][Ee][Ll][Ee][Aa][Ss][Ee]") add_definitions(-DLLARP_RELEASE_MOTTO="${RELEASE_MOTTO}") endif() -set(LOKINET_VERSION "${lokinet_VERSION_MAJOR}.${lokinet_VERSION_MINOR}.${lokinet_VERSION_PATCH}") - list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") # Core options diff --git a/contrib/macos/Info.plist.in b/contrib/macos/Info.plist.in index 5e09e839b..9311f2404 100644 --- a/contrib/macos/Info.plist.in +++ b/contrib/macos/Info.plist.in @@ -17,8 +17,8 @@ CFBundlePackageType XPC! CFBundleShortVersionString - @LOKINET_VERSION@ + @lokinet_VERSION@ CFBundleVersion - @LOKINET_VERSION@.@LOKINET_APPLE_BUILD@ + @lokinet_VERSION@.@LOKINET_APPLE_BUILD@ diff --git a/contrib/macos/LokinetExtension.Info.plist.in b/contrib/macos/LokinetExtension.Info.plist.in index 30dc5f8ea..80afb1b94 100644 --- a/contrib/macos/LokinetExtension.Info.plist.in +++ b/contrib/macos/LokinetExtension.Info.plist.in @@ -21,7 +21,7 @@ lokinet CFBundleVersion - @LOKINET_VERSION@ + @lokinet_VERSION@ ITSAppUsesNonExemptEncryption diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index deb60ed0f..b6fd20917 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -98,7 +98,7 @@ if(APPLE) 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_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" From 2b8ef416c302cf685f89837fff8364917bd5f57e Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 2 Sep 2021 19:13:51 -0300 Subject: [PATCH 35/45] Remove old mac installer packaging --- CMakeLists.txt | 2 +- cmake/installer.cmake | 4 --- cmake/macos_installer_deps.cmake | 56 -------------------------------- 3 files changed, 1 insertion(+), 61 deletions(-) delete mode 100644 cmake/macos_installer_deps.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 105ce499d..bb2983c51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -357,6 +357,6 @@ if(NOT TARGET uninstall) endif() -if(BUILD_PACKAGE) +if(BUILD_PACKAGE AND NOT APPLE) include(cmake/installer.cmake) endif() diff --git a/cmake/installer.cmake b/cmake/installer.cmake index b08a9d7b4..b8c04e563 100644 --- a/cmake/installer.cmake +++ b/cmake/installer.cmake @@ -7,10 +7,6 @@ if(WIN32) include(cmake/win32_installer_deps.cmake) endif() -if(APPLE) - include(cmake/macos_installer_deps.cmake) -endif() - # This must always be last! include(CPack) diff --git a/cmake/macos_installer_deps.cmake b/cmake/macos_installer_deps.cmake deleted file mode 100644 index b315b389b..000000000 --- a/cmake/macos_installer_deps.cmake +++ /dev/null @@ -1,56 +0,0 @@ -# macos specific cpack stuff goes here - -return() - -# Here we build lokinet-network-control-panel into 'lokinet-gui.app' in "extra/" where a postinstall -# script will then move it to /Applications/. -set(LOKINET_GUI_REPO "https://github.com/oxen-io/loki-network-control-panel.git" - CACHE STRING "Can be set to override the default lokinet-gui git repository") -set(LOKINET_GUI_CHECKOUT "origin/master" - CACHE STRING "Can be set to specify a particular branch or tag to build from LOKINET_GUI_REPO") -set(MACOS_SIGN_APP "" # FIXME: it doesn't use a Apple Distribution key because WTF knows. - CACHE STRING "enable codesigning of the stuff inside the .app and the lokinet binary -- use a 'Apple Distribution' key (or description) from `security find-identity -v`") -set(MACOS_SIGN_PKG "" - CACHE STRING "enable codesigning of the .pkg -- use a 'Developer ID Installer' key (or description) from `security find-identity -v`") -set(MACOS_NOTARIZE_USER "" - CACHE STRING "set macos notarization username; can also set it in ~/.notarization.cmake") -set(MACOS_NOTARIZE_PASS "" - CACHE STRING "set macos notarization password; can also set it in ~/.notarization.cmake") -set(MACOS_NOTARIZE_ASC "" - CACHE STRING "set macos notarization asc provider; can also set it in ~/.notarization.cmake") - -if(NOT BUILD_STATIC_DEPS) - message(FATAL_ERROR "Building an installer on macos requires -DBUILD_STATIC_DEPS=ON") -endif() - -#set(CPACK_GENERATOR "Bundle") - -#set(MACOSX_BUNDLE_BUNDLE_NAME Lokinet) -#set(CPACK_BUNDLE_NAME Lokinet) -#set(CPACK_BUNDLE_PLIST ${CMAKE_SOURCE_DIR}/contrib/macos/Info.plist) -#set(CPACK_BUNDLE_ICON "${CMAKE_CURRENT_BINARY_DIR}/lokinet.icns") -#set(CPACK_BUNDLE_STARTUP_COMMAND ${CMAKE_BINARY_DIR}/daemon/lokinet) -#set(MACOSX_BUNDLE_GUI_IDENTIFIER org.lokinet.lokinet) -#set(MACOSX_BUNDLE_INFO_STRING "Lokinet IP Packet Onion Router") -#set(MACOSX_BUNDLE_LONG_VERSION_STRING ${PROJECT_VERSION}) -#set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}) -#set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}) -#set(MACOSX_BUNDLE_COPYRIGHT "© 2021, The Loki Project") -#set(CPACK_BUNDLE_APPLE_ENTITLEMENTS ${CMAKE_SOURCE_DIR}/contrib/macos/lokinet.entitlements) -#set(CPACK_BUNDLE_APPLE_CERT_APP "${MACOS_SIGN_APP}") - -if(MACOS_SIGN_APP AND MACOS_SIGN_PKG) - if(NOT MACOS_NOTARIZE_USER) - if(EXISTS "$ENV{HOME}/.notarization.cmake") - include("$ENV{HOME}/.notarization.cmake") - endif() - endif() - if(MACOS_NOTARIZE_USER AND MACOS_NOTARIZE_PASS AND MACOS_NOTARIZE_ASC) - message(STATUS "'notarization' target enabled") - configure_file(${CMAKE_SOURCE_DIR}/contrib/macos/notarize.py.in ${CMAKE_CURRENT_BINARY_DIR}/contrib/notarize.py ESCAPE_QUOTES @ONLY) - file(COPY ${CMAKE_CURRENT_BINARY_DIR}/contrib/notarize.py DESTINATION ${PROJECT_BINARY_DIR} FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE) - add_custom_target(notarize ./notarize.py) - else() - message(WARNING "Not enable 'notarization' target: signing is enabled but notarization info not provided. Create ~/.notarization.cmake or set cmake parameters directly") - endif() -endif() From 12e00b7a99eaea64cb3c171c794533201d6cb8b3 Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 2 Sep 2021 19:14:33 -0300 Subject: [PATCH 36/45] Remove advertising of big crappy company --- contrib/lokinet.svg | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/lokinet.svg b/contrib/lokinet.svg index f8e760248..896e74bbb 100644 --- a/contrib/lokinet.svg +++ b/contrib/lokinet.svg @@ -1,5 +1,4 @@ -