initial network extension code for macos

probably does not work
pull/1688/head
jeff 3 years ago committed by Jeff Becker
parent 63ed5c16ed
commit 0708a0d897
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -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)

@ -14,3 +14,4 @@ endif()
# This must always be last!
include(CPack)

@ -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=$<TARGET_FILE:oxenmq::oxenmq>$<SEMICOLON>$<TARGET_FILE:libzmq>$<SEMICOLON>$<TARGET_FILE:sodium>"
"-DOXENMQ_INCLUDE_DIRS=$<TARGET_PROPERTY:oxenmq::oxenmq,INCLUDE_DIRECTORIES>"
)
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 $<TARGET_FILE:lokinet> $<TARGET_FILE:lokinet-vpn>
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)

@ -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 '</replacement>' | wc -l)
if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.[hc](pp)?$' | grep -v '\#') | grep '</replacement>' | 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

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 189.4 189.4" style="enable-background:new 0 0 189.4 189.4;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
</style>
<g>
<polygon class="st0" points="113.6,132.6 94.7,151.5 75.8,132.6 56.8,151.5 94.7,189.4 132.6,151.5 "/>
<polygon class="st0" points="132.6,113.6 151.5,94.7 132.6,75.8 151.5,56.8 189.4,94.7 151.5,132.6 "/>
<polygon class="st0" points="56.8,75.8 37.9,94.7 56.8,113.6 37.9,132.6 0,94.7 37.9,56.8 "/>
<polygon class="st0" points="75.8,56.8 94.7,37.9 113.6,56.8 132.6,37.9 94.7,0 56.8,37.9 "/>
<rect x="100.2" y="100.2" transform="matrix(0.7071 0.7071 -0.7071 0.7071 113.6329 -47.0683)" class="st0" width="26.8" height="26.8"/>
<rect x="62.4" y="62.4" transform="matrix(0.7071 0.7071 -0.7071 0.7071 75.7552 -31.3789)" class="st0" width="26.8" height="26.8"/>
<rect x="100.2" y="62.4" transform="matrix(0.7071 0.7071 -0.7071 0.7071 86.8493 -58.1624)" class="st0" width="26.8" height="26.8"/>
<rect x="62.4" y="100.2" transform="matrix(0.7071 0.7071 -0.7071 0.7071 102.5388 -20.2848)" class="st0" width="26.8" height="26.8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -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

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Lokinet</string>
<key>CFBundleExecutable</key>
<string>MacOS/lokinet</string>
<key>CFBundleIdentifier</key>
<string>org.lokinet.Daemon</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>lokinet</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>0.1</string>
<key>CFBundleVersion</key>
<string>0.1</string>
</dict>
</plist>

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Lokinet</string>
<key>CFBundleExecutable</key>
<string>lokinet-extension</string>
<key>CFBundleIdentifier</key>
<string>org.lokinet.NetworkExtension</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Lokinet</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>0.1</string>
<key>CFBundleVersion</key>
<string>0.1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.networkextension.packet-tunnel</string>
<key>NSExtensionPrincipalClass</key>
<string>Lokinet.LLARPPacketTunnel</string>
</dict>
</dict>
</plist>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
</dict>
</plist>

@ -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}"

@ -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

@ -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/" $<TARGET_FILE:lokinet>
# )
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()

@ -0,0 +1,4 @@
module LokinetExtension {
header "@CMAKE_SOURCE_DIR@/include/lokinet-extension.hpp"
}

@ -0,0 +1,9 @@
#import <Foundation/Foundation.h>
#include <NetworkExtension/NetworkExtension.h>
int main (int argc, const char * argv[])
{
return 0;
}

@ -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()

@ -0,0 +1,4 @@
module Lokinet {
header "lokinet-extension.hpp"
}

@ -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")
}
}

@ -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)

@ -120,7 +120,6 @@ namespace llarp
std::unique_ptr<std::promise<void>> closeWaiter;
};
} // namespace llarp
#endif

@ -0,0 +1,18 @@
#pragma once
#include <Foundation/Foundation.h>
#include <NetworkExtension/NetworkExtension.h>
struct ContextWrapper;
@interface LLARPPacketTunnel : NEPacketTunnelProvider
{
@private
struct ContextWrapper* m_Context;
}
- (void)startTunnelWithOptions:(NSDictionary<NSString*, NSObject*>*)options
completionHandler:(void (^)(NSError* error))completionHandler;
- (void)stopTunnelWithReason:(NEProviderStopReason)reason
completionHandler:(void (^)(void))completionHandler;
@end

@ -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()

@ -1446,4 +1446,18 @@ namespace llarp
return config;
}
#ifdef __APPLE__
std::shared_ptr<Config>
Config::NetworkExtensionConfig()
{
auto config = std::make_shared<Config>(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

@ -260,6 +260,11 @@ namespace llarp
static std::shared_ptr<Config>
EmbeddedConfig();
#ifdef __APPLE__
static std::shared_ptr<Config>
NetworkExtensionConfig();
#endif
private:
/// Load (initialize) a default config.
///

@ -0,0 +1,202 @@
#include <lokinet-extension.hpp>
#include <llarp.hpp>
#include <llarp/config/config.hpp>
#include <llarp/ev/vpn.hpp>
#include <llarp/util/thread/queue.hpp>
#include <string>
namespace llarp::apple
{
struct FrameworkContext : public llarp::Context
{
explicit FrameworkContext(NEPacketTunnelProvider * tunnel);
~FrameworkContext() {}
std::shared_ptr<vpn::Platform>
makeVPNPlatform() override;
void
Start();
private:
NEPacketTunnelProvider * m_Tunnel;
std::unique_ptr<std::thread> m_Runner;
};
class VPNInterface final : public vpn::NetworkInterface
{
NEPacketTunnelProvider * m_Tunnel;
static inline constexpr auto PacketQueueSize = 1024;
thread::Queue<net::IPPacket> m_ReadQueue;
void
OfferReadPacket(NSData * data)
{
llarp::net::IPPacket pkt;
const llarp_buffer_t buf{static_cast<const uint8_t *>(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<NSData*> * packets, NSArray<NSNumber*> *)
{
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<vpn::NetworkInterface>
ObtainInterface(vpn::InterfaceInfo) override
{
return std::make_shared<VPNInterface>(m_Tunnel);
}
};
FrameworkContext::FrameworkContext(NEPacketTunnelProvider * tunnel) :
llarp::Context{},
m_Tunnel{tunnel}
{
}
void
FrameworkContext::Start()
{
std::promise<void> result;
m_Runner = std::make_unique<std::thread>(
[&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<vpn::Platform>
FrameworkContext::makeVPNPlatform()
{
return std::make_shared<VPNPlatform>(m_Tunnel);
}
}
struct ContextWrapper
{
std::shared_ptr<llarp::apple::FrameworkContext> m_Context;
public:
explicit ContextWrapper(NEPacketTunnelProvider * tunnel) :
m_Context{std::make_shared<llarp::apple::FrameworkContext>(tunnel)}
{}
void
Start()
{
m_Context->Start();
}
void
Stop()
{
m_Context->CloseAsync();
m_Context->Wait();
}
};
@implementation LLARPPacketTunnel
- (void)startTunnelWithOptions:(NSDictionary<NSString *,NSObject *> *)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

@ -1,173 +0,0 @@
#pragma once
#include <llarp/ev/vpn.hpp>
#include "common.hpp"
#include <sys/kern_control.h>
#include <sys/sys_domain.h>
#include <sys/kern_event.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <ifaddrs.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
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<size_t>(n) == pkt.sz;
}
return false;
}
};
class ApplePlatform : public Platform
{
public:
std::shared_ptr<NetworkInterface>
ObtainInterface(InterfaceInfo info) override
{
return std::make_shared<AppleInterface>(std::move(info));
}
};
} // namespace llarp::vpn

@ -1,3 +1,6 @@
#include <llarp/ev/vpn.hpp>
#ifdef _WIN32
#include "win32.hpp"
#endif
@ -8,9 +11,8 @@
#include "linux.hpp"
#endif
#endif
#ifdef __APPLE__
#include "apple.hpp"
#endif
#include <exception>
namespace llarp::vpn
{
@ -30,7 +32,7 @@ namespace llarp::vpn
#endif
#endif
#ifdef __APPLE__
plat = std::make_shared<vpn::ApplePlatform>();
throw std::runtime_error{"not supported"};
#endif
return plat;
}

@ -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

Loading…
Cancel
Save