mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-18 17:05:49 +03:00
Compare commits
30 Commits
bugfix/lin
...
support_16
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81050542cf | ||
|
|
38c0c1ec5d | ||
|
|
32b985942a | ||
|
|
1cfe6a1e50 | ||
|
|
132b6bc083 | ||
|
|
2b5c2cb021 | ||
|
|
729d6ee6d3 | ||
|
|
cd87253844 | ||
|
|
8cdaa0c2ee | ||
|
|
d563d66b28 | ||
|
|
37327e30d3 | ||
|
|
e0af63ce1c | ||
|
|
041d0fcab5 | ||
|
|
2a6960a4fb | ||
|
|
8481367fb6 | ||
|
|
70d6f9996d | ||
|
|
616d58e901 | ||
|
|
0bfbd82536 | ||
|
|
544ad4ba6e | ||
|
|
02be6dc5f9 | ||
|
|
bfcf7f0305 | ||
|
|
2bce595ade | ||
|
|
cd1e561fd4 | ||
|
|
9bd1e6a0f5 | ||
|
|
5058c9aa6f | ||
|
|
d78416835c | ||
|
|
40e6c6aae3 | ||
|
|
911a999c64 | ||
|
|
b4f4184aa6 | ||
|
|
5c6db4b7a4 |
@@ -1,7 +1,36 @@
|
||||
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||
|
||||
set(PROJECT AmneziaVPN)
|
||||
set(AMNEZIAVPN_VERSION 4.8.13.0)
|
||||
set(AMNEZIAVPN_VERSION 4.8.13.1)
|
||||
|
||||
include(cmake/conan_bootstrap.cmake)
|
||||
set(CMAKE_PROJECT_TOP_LEVEL_INCLUDES ${CMAKE_SOURCE_DIR}/cmake/conan_provider.cmake)
|
||||
|
||||
if(APPLE)
|
||||
get_property(generator_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if (generator_is_multi_config)
|
||||
set(CONAN_INSTALL_BUILD_CONFIGURATIONS Release Debug MinSizeRel RelWithDebInfo)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "14.0" CACHE STRING "" FORCE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "" FORCE)
|
||||
elseif(MACOS_NE)
|
||||
set(CONAN_INSTALL_ARGS "--build=missing;-o=&:macos_ne=True" CACHE STRING "" FORCE)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0" CACHE STRING "" FORCE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
|
||||
else()
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0" CACHE STRING "" FORCE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
set(CONAN_INSTALL_ARGS
|
||||
"--build=missing"
|
||||
"-o=*:page_16k=True"
|
||||
"-e=*:LDFLAGS=-Wl,-z,max-page-size=16384"
|
||||
CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}
|
||||
DESCRIPTION "AmneziaVPN"
|
||||
@@ -12,7 +41,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||
|
||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
set(APP_ANDROID_VERSION_CODE 2106)
|
||||
set(APP_ANDROID_VERSION_CODE 2107)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(MZ_PLATFORM_NAME "linux")
|
||||
@@ -32,16 +61,6 @@ set(QT_BUILD_TOOLS_WHEN_CROSS_COMPILING ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(APPLE)
|
||||
if(IOS)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64")
|
||||
elseif(MACOS_NE)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
|
||||
else()
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(client)
|
||||
|
||||
if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||
@@ -61,6 +80,7 @@ if(WIN32 AND NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||
set(CPACK_PACKAGE_VENDOR "AmneziaVPN")
|
||||
set(CPACK_PACKAGE_VERSION ${AMNEZIAVPN_VERSION})
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "AmneziaVPN client")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "AmneziaVPN")
|
||||
set(CPACK_PACKAGE_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
set(CPACK_PACKAGE_EXECUTABLES "AmneziaVPN" "AmneziaVPN")
|
||||
|
||||
Submodule client/3rd-prebuilt updated: 579673b2ed...b8c229288d
@@ -37,10 +37,6 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||
set(PACKAGES ${PACKAGES} Widgets)
|
||||
endif()
|
||||
|
||||
if(LINUX AND NOT ANDROID)
|
||||
list(APPEND PACKAGES QuickTemplates2 QmlModels OpenGL)
|
||||
endif()
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS ${PACKAGES})
|
||||
|
||||
set(LIBS ${LIBS}
|
||||
@@ -55,24 +51,14 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||
endif()
|
||||
|
||||
qt_standard_project_setup()
|
||||
qt_add_executable(${PROJECT} MANUAL_FINALIZATION)
|
||||
|
||||
if(LINUX AND NOT ANDROID)
|
||||
target_link_options(${PROJECT} PRIVATE "-Wl,--no-as-needed")
|
||||
target_link_options(${PROJECT} PRIVATE "LINKER:--disable-new-dtags")
|
||||
set_target_properties(${PROJECT} PROPERTIES
|
||||
BUILD_RPATH "\$ORIGIN/../lib"
|
||||
INSTALL_RPATH "\$ORIGIN/../lib"
|
||||
INSTALL_RPATH_USE_LINK_PATH FALSE
|
||||
)
|
||||
set_property(TARGET ${PROJECT} PROPERTY BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
|
||||
target_link_libraries(${PROJECT} PRIVATE
|
||||
Qt6::QuickTemplates2
|
||||
Qt6::QmlModels
|
||||
Qt6::OpenGL
|
||||
)
|
||||
# 16KB page size support for Android 15+ / Google Play
|
||||
# Must be set before any targets are defined so it applies to all compiled-from-source libraries
|
||||
if(ANDROID)
|
||||
add_link_options("-Wl,-z,max-page-size=16384")
|
||||
endif()
|
||||
|
||||
qt_add_executable(${PROJECT} MANUAL_FINALIZATION)
|
||||
target_include_directories(${PROJECT} PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
|
||||
)
|
||||
@@ -80,7 +66,6 @@ target_include_directories(${PROJECT} PUBLIC
|
||||
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
|
||||
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_interface.rep)
|
||||
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_interface.rep)
|
||||
qt_add_repc_replicas(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../ipc/ipc_process_tun2socks.rep)
|
||||
endif()
|
||||
|
||||
qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/resources.qrc)
|
||||
@@ -216,17 +201,6 @@ elseif(APPLE)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${PROJECT} PRIVATE ${LIBS})
|
||||
|
||||
if(LINUX AND NOT ANDROID)
|
||||
target_link_libraries(${PROJECT} PRIVATE
|
||||
"-Wl,--push-state,--no-as-needed"
|
||||
Qt6::QuickTemplates2
|
||||
Qt6::QmlModels
|
||||
Qt6::OpenGL
|
||||
"-Wl,--pop-state"
|
||||
)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${PROJECT} PRIVATE "MZ_$<UPPER_CASE:${MZ_PLATFORM_NAME}>")
|
||||
|
||||
# deploy artifacts required to run the application to the debug build folder
|
||||
@@ -250,13 +224,6 @@ if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
COMMAND_EXPAND_LISTS
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:Debug>,copy_directory,true>
|
||||
${CMAKE_SOURCE_DIR}/client/3rd-prebuilt/deploy-prebuilt/${DEPLOY_PLATFORM_PATH}
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
COMMAND_EXPAND_LISTS
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(${PROJECT} PRIVATE ${SOURCES} ${HEADERS} ${RESOURCES} ${QRC} ${I18NQRC})
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
[versions]
|
||||
agp = "8.5.2"
|
||||
agp = "8.6.1"
|
||||
kotlin = "1.9.24"
|
||||
androidx-core = "1.13.1"
|
||||
androidx-activity = "1.9.1"
|
||||
androidx-annotation = "1.8.2"
|
||||
androidx-biometric = "1.2.0-alpha05"
|
||||
androidx-camera = "1.3.4"
|
||||
androidx-camera = "1.5.3"
|
||||
androidx-fragment = "1.8.2"
|
||||
androidx-security-crypto = "1.1.0-alpha06"
|
||||
androidx-datastore = "1.1.1"
|
||||
|
||||
@@ -90,6 +90,10 @@ class AmneziaActivity : QtActivity() {
|
||||
|
||||
private val actionResultHandlers = mutableMapOf<Int, ActivityResultHandler>()
|
||||
private val permissionRequestHandlers = mutableMapOf<Int, PermissionRequestHandler>()
|
||||
|
||||
private var isActivityResumed = false
|
||||
private var hasWindowFocus = false
|
||||
private val resumeHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
private val vpnServiceEventHandler: Handler by lazy(NONE) {
|
||||
object : Handler(Looper.getMainLooper()) {
|
||||
@@ -199,10 +203,7 @@ class AmneziaActivity : QtActivity() {
|
||||
|
||||
private fun loadLibs() {
|
||||
listOf(
|
||||
"rsapss",
|
||||
"crypto_3",
|
||||
"ssl_3",
|
||||
"ssh"
|
||||
"rsapss"
|
||||
).forEach {
|
||||
loadSharedLibrary(this.applicationContext, it)
|
||||
}
|
||||
@@ -262,6 +263,10 @@ class AmneziaActivity : QtActivity() {
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
isActivityResumed = false
|
||||
hasWindowFocus = false
|
||||
// Cancel all pending operations when activity stops
|
||||
resumeHandler.removeCallbacksAndMessages(null)
|
||||
Log.d(TAG, "Stop Amnezia activity")
|
||||
doUnbindService()
|
||||
mainScope.launch {
|
||||
@@ -273,7 +278,13 @@ class AmneziaActivity : QtActivity() {
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
hasWindowFocus = hasFocus
|
||||
Log.d(TAG, "Window focus changed: hasFocus=$hasFocus")
|
||||
|
||||
// Cancel pending operations if window loses focus
|
||||
if (!hasFocus) {
|
||||
resumeHandler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
@@ -316,30 +327,42 @@ class AmneziaActivity : QtActivity() {
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
isActivityResumed = false
|
||||
// Cancel all pending operations when activity pauses
|
||||
resumeHandler.removeCallbacksAndMessages(null)
|
||||
Log.d(TAG, "Pause Amnezia activity")
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
/* if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
isActivityResumed = true
|
||||
Log.d(TAG, "Resume Amnezia activity")
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
window.decorView.apply {
|
||||
invalidate()
|
||||
|
||||
postDelayed({
|
||||
sendTouch(1f, 1f)
|
||||
resumeHandler.postDelayed({
|
||||
// Check if activity is still resumed and has focus before executing
|
||||
if (isActivityResumed && hasWindowFocus && !isFinishing && !isDestroyed) {
|
||||
sendTouch(1f, 1f)
|
||||
}
|
||||
}, 100)
|
||||
|
||||
postDelayed({
|
||||
sendTouch(2f, 2f)
|
||||
resumeHandler.postDelayed({
|
||||
if (isActivityResumed && hasWindowFocus && !isFinishing && !isDestroyed) {
|
||||
sendTouch(2f, 2f)
|
||||
}
|
||||
}, 200)
|
||||
|
||||
postDelayed({
|
||||
requestLayout()
|
||||
invalidate()
|
||||
resumeHandler.postDelayed({
|
||||
if (isActivityResumed && hasWindowFocus && !isFinishing && !isDestroyed) {
|
||||
requestLayout()
|
||||
invalidate()
|
||||
}
|
||||
}, 250)
|
||||
}
|
||||
} */
|
||||
Log.d(TAG, "Resume Amnezia activity")
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureWindowForEdgeToEdge() {
|
||||
@@ -402,6 +425,10 @@ class AmneziaActivity : QtActivity() {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
isActivityResumed = false
|
||||
hasWindowFocus = false
|
||||
// Cancel all pending operations when activity is destroyed
|
||||
resumeHandler.removeCallbacksAndMessages(null)
|
||||
Log.d(TAG, "Destroy Amnezia activity")
|
||||
unregisterBroadcastReceiver(notificationStateReceiver)
|
||||
notificationStateReceiver = null
|
||||
|
||||
@@ -8,76 +8,6 @@ include(${CLIENT_ROOT_DIR}/cmake/QSimpleCrypto.cmake)
|
||||
|
||||
include(${CLIENT_ROOT_DIR}/3rd/qrcodegen/qrcodegen.cmake)
|
||||
|
||||
set(LIBSSH_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/libssh/")
|
||||
set(OPENSSL_ROOT_DIR "${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/openssl/")
|
||||
|
||||
set(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib")
|
||||
|
||||
if(WIN32)
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/windows/include")
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/windows/x86_64/ssh.lib")
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/windows/x86_64")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/windows/win64/libssl.lib")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win64/libcrypto.lib")
|
||||
else()
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/windows/x86/ssh.lib")
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/windows/x86")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libssl.lib")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libcrypto.lib")
|
||||
endif()
|
||||
elseif(APPLE AND NOT IOS)
|
||||
if(MACOS_NE)
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/universal2/libssh.a")
|
||||
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/universal2/libz.a")
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/universal2")
|
||||
else()
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libssh.a")
|
||||
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/macos/x86_64/libz.a")
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/macos/x86_64")
|
||||
endif()
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/macos/include")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libssl.a")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libcrypto.a")
|
||||
elseif(IOS)
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/ios/arm64")
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/ios/arm64/libssh.a")
|
||||
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/ios/arm64/libz.a")
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/ios/iphone/include")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/ios/iphone/lib/libssl.a")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/ios/iphone/lib/libcrypto.a")
|
||||
elseif(ANDROID)
|
||||
set(abi ${CMAKE_ANDROID_ARCH_ABI})
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/android/${abi}")
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/android/${abi}/libssh.so")
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/android/include")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/android/${abi}/libssl.a")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/android/${abi}/libcrypto.a")
|
||||
set(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/android/${abi}")
|
||||
elseif(LINUX)
|
||||
set(LIBSSH_INCLUDE_DIR "${LIBSSH_ROOT_DIR}/linux/x86_64")
|
||||
set(ZLIB_LIB_PATH "${LIBSSH_ROOT_DIR}/linux/x86_64/libz.a")
|
||||
set(LIBSSH_LIB_PATH "${LIBSSH_ROOT_DIR}/linux/x86_64/libssh.a")
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/linux/include")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/linux/x86_64/libssl.a")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/linux/x86_64/libcrypto.a")
|
||||
endif()
|
||||
|
||||
file(COPY ${OPENSSL_LIB_SSL_PATH} ${OPENSSL_LIB_CRYPTO_PATH}
|
||||
DESTINATION ${OPENSSL_LIBRARIES_DIR})
|
||||
|
||||
set(OPENSSL_USE_STATIC_LIBS TRUE)
|
||||
|
||||
set(LIBS ${LIBS}
|
||||
${LIBSSH_LIB_PATH}
|
||||
${ZLIB_LIB_PATH}
|
||||
)
|
||||
|
||||
set(LIBS ${LIBS}
|
||||
${OPENSSL_LIB_SSL_PATH}
|
||||
${OPENSSL_LIB_CRYPTO_PATH}
|
||||
)
|
||||
|
||||
add_compile_definitions(_WINSOCKAPI_)
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||
@@ -106,12 +36,20 @@ endif()
|
||||
set(LIBS ${LIBS} qt6keychain)
|
||||
|
||||
include_directories(
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${LIBSSH_INCLUDE_DIR}/include
|
||||
${LIBSSH_ROOT_DIR}/include
|
||||
${CLIENT_ROOT_DIR}/3rd/libssh/include
|
||||
${CLIENT_ROOT_DIR}/3rd/QSimpleCrypto/src/include
|
||||
${CLIENT_ROOT_DIR}/3rd/qtkeychain/qtkeychain
|
||||
${CMAKE_CURRENT_BINARY_DIR}/3rd/qtkeychain
|
||||
${CMAKE_CURRENT_BINARY_DIR}/3rd/libssh/include
|
||||
)
|
||||
|
||||
if(ANDROID)
|
||||
find_package(android-openssl REQUIRED)
|
||||
# CMakeConfigDeps doesn't propagate include dirs onto IMPORTED targets;
|
||||
# use the legacy variable that IS correctly populated by the config file.
|
||||
include_directories(${android-openssl_INCLUDE_DIRS})
|
||||
else()
|
||||
find_package(openssl REQUIRED)
|
||||
endif()
|
||||
list(APPEND LIBS OpenSSL::SSL OpenSSL::Crypto)
|
||||
|
||||
find_package(libssh REQUIRED)
|
||||
list(APPEND LIBS ssh::ssh)
|
||||
|
||||
@@ -42,18 +42,14 @@ set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.cpp
|
||||
)
|
||||
|
||||
foreach(abi IN ITEMS ${QT_ANDROID_ABIS})
|
||||
set_property(TARGET ${PROJECT} PROPERTY QT_ANDROID_EXTRA_LIBS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/amneziawg/android/${abi}/libwg-go.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/android/${abi}/libck-ovpn-plugin.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/android/${abi}/libovpn3.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/android/${abi}/libovpnutil.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/android/${abi}/librsapss.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openssl/android/${abi}/libcrypto_3.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openssl/android/${abi}/libssl_3.so
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/libssh/android/${abi}/libssh.so
|
||||
)
|
||||
endforeach()
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/xray/android/libxray.aar
|
||||
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/android/xray/libXray)
|
||||
find_package(awg-android REQUIRED)
|
||||
set(LIBS ${LIBS} amnezia::awg-android)
|
||||
set_property(TARGET ${PROJECT} APPEND PROPERTY QT_ANDROID_EXTRA_LIBS ${AMNEZIA_ANDROID_LIBWG_PATH} ${AMNEZIA_ANDROID_LIBWG_QUICK_PATH})
|
||||
|
||||
find_package(amnezia-libxray REQUIRED)
|
||||
file(COPY ${AMNEZIA_LIBXRAY_PATH} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/android/xray/libXray)
|
||||
|
||||
find_package(openvpn-pt-android REQUIRED)
|
||||
set(LIBS ${LIBS} amnezia::openvpn-pt-android)
|
||||
set_property(TARGET ${PROJECT} APPEND PROPERTY QT_ANDROID_EXTRA_LIBS ${OPENVPN_PT_ANDROID_LIBCK_OVPN_PLUGIN_PATH})
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
message("Client iOS build")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 13.0)
|
||||
set(APPLE_PROJECT_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
|
||||
|
||||
enable_language(OBJC)
|
||||
enable_language(OBJCXX)
|
||||
enable_language(Swift)
|
||||
@@ -137,11 +135,3 @@ set_property(TARGET ${PROJECT} APPEND PROPERTY RESOURCE
|
||||
|
||||
add_subdirectory(ios/networkextension)
|
||||
add_dependencies(${PROJECT} networkextension)
|
||||
|
||||
set_property(TARGET ${PROJECT} PROPERTY XCODE_EMBED_FRAMEWORKS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-ios/OpenVPNAdapter.framework"
|
||||
)
|
||||
|
||||
set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-ios/)
|
||||
target_link_libraries("networkextension" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-ios/OpenVPNAdapter.framework")
|
||||
|
||||
|
||||
@@ -23,9 +23,6 @@ set_target_properties(${PROJECT} PROPERTIES
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
|
||||
)
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE INTERNAL "" FORCE)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
||||
|
||||
|
||||
set(HEADERS ${HEADERS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/macos_util.h
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
message("Client ==> MacOS NE build")
|
||||
|
||||
set_target_properties(${PROJECT} PROPERTIES MACOSX_BUNDLE TRUE)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
||||
|
||||
set(APPLE_PROJECT_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
|
||||
@@ -152,19 +151,6 @@ message(${QtCore_location})
|
||||
|
||||
get_filename_component(QT_BIN_DIR_DETECTED "${QtCore_location}/../../../../../bin" ABSOLUTE)
|
||||
|
||||
set_property(TARGET ${PROJECT} PROPERTY XCODE_EMBED_FRAMEWORKS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos/OpenVPNAdapter.framework"
|
||||
)
|
||||
|
||||
set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos)
|
||||
target_link_libraries("AmneziaVPNNetworkExtension" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/3rd-prebuilt/3rd-prebuilt/openvpn/apple/OpenVPNAdapter-macos/OpenVPNAdapter.framework")
|
||||
|
||||
add_custom_command(TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
$<TARGET_BUNDLE_DIR:AmneziaVPN>/Contents/Frameworks
|
||||
COMMAND /usr/bin/find "$<TARGET_BUNDLE_DIR:AmneziaVPN>/Contents/Frameworks/OpenVPNAdapter.framework" -name "*.sha256" -delete
|
||||
COMMAND /usr/bin/codesign --force --sign "Apple Distribution"
|
||||
"$<TARGET_BUNDLE_DIR:AmneziaVPN>/Contents/Frameworks/OpenVPNAdapter.framework/Versions/Current/OpenVPNAdapter"
|
||||
COMMAND ${QT_BIN_DIR_DETECTED}/macdeployqt $<TARGET_BUNDLE_DIR:AmneziaVPN> -appstore-compliant -qmldir=${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Signing OpenVPNAdapter framework"
|
||||
)
|
||||
|
||||
@@ -181,7 +181,6 @@ if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
|
||||
|
||||
set(HEADERS ${HEADERS}
|
||||
${CLIENT_ROOT_DIR}/core/ipcclient.h
|
||||
${CLIENT_ROOT_DIR}/core/privileged_process.h
|
||||
${CLIENT_ROOT_DIR}/ui/systemtray_notificationhandler.h
|
||||
${CLIENT_ROOT_DIR}/protocols/openvpnprotocol.h
|
||||
${CLIENT_ROOT_DIR}/protocols/openvpnovercloakprotocol.h
|
||||
@@ -194,7 +193,6 @@ if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
|
||||
|
||||
set(SOURCES ${SOURCES}
|
||||
${CLIENT_ROOT_DIR}/core/ipcclient.cpp
|
||||
${CLIENT_ROOT_DIR}/core/privileged_process.cpp
|
||||
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
|
||||
${CLIENT_ROOT_DIR}/ui/systemtray_notificationhandler.cpp
|
||||
${CLIENT_ROOT_DIR}/protocols/openvpnprotocol.cpp
|
||||
|
||||
@@ -7,7 +7,6 @@ IpcClient::IpcClient(QObject *parent) : QObject(parent)
|
||||
{
|
||||
m_node.connectToNode(QUrl("local:" + amnezia::getIpcServiceUrl()));
|
||||
m_interface.reset(m_node.acquire<IpcInterfaceReplica>());
|
||||
m_tun2socks.reset(m_node.acquire<IpcProcessTun2SocksReplica>());
|
||||
}
|
||||
|
||||
IpcClient& IpcClient::Instance()
|
||||
@@ -33,68 +32,43 @@ QSharedPointer<IpcInterfaceReplica> IpcClient::Interface()
|
||||
return rep;
|
||||
}
|
||||
|
||||
QSharedPointer<IpcProcessTun2SocksReplica> IpcClient::InterfaceTun2Socks()
|
||||
QSharedPointer<IpcProcessInterfaceReplica> IpcClient::CreatePrivilegedProcess()
|
||||
{
|
||||
QSharedPointer<IpcProcessTun2SocksReplica> rep = Instance().m_tun2socks;
|
||||
if (rep.isNull()) {
|
||||
qCritical() << "IpcClient::InterfaceTun2Socks: Replica is undefined";
|
||||
return nullptr;
|
||||
}
|
||||
if (!rep->waitForSource(1000)) {
|
||||
qCritical() << "IpcClient::InterfaceTun2Socks: Failed to initialize replica";
|
||||
return nullptr;
|
||||
}
|
||||
if (!rep->isReplicaValid()) {
|
||||
qWarning() << "IpcClient::InterfaceTun2Socks(): Replica is invalid";
|
||||
}
|
||||
return rep;
|
||||
}
|
||||
|
||||
QSharedPointer<PrivilegedProcess> IpcClient::CreatePrivilegedProcess()
|
||||
{
|
||||
QSharedPointer<IpcInterfaceReplica> rep = Interface();
|
||||
if (!rep) {
|
||||
qCritical() << "IpcClient::createPrivilegedProcess: Replica is invalid";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QRemoteObjectPendingReply<int> pidReply = rep->createPrivilegedProcess();
|
||||
if (!pidReply.waitForFinished(5000)){
|
||||
qCritical() << "IpcClient::createPrivilegedProcess: Failed to execute RO createPrivilegedProcess call";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int pid = pidReply.returnValue();
|
||||
QSharedPointer<ProcessDescriptor> pd(new ProcessDescriptor());
|
||||
|
||||
pd->localSocket.reset(new QLocalSocket(pd->replicaNode.data()));
|
||||
|
||||
connect(pd->localSocket.data(), &QLocalSocket::connected, pd->replicaNode.data(), [pd]() {
|
||||
pd->replicaNode->addClientSideConnection(pd->localSocket.data());
|
||||
|
||||
IpcProcessInterfaceReplica *repl = pd->replicaNode->acquire<IpcProcessInterfaceReplica>();
|
||||
// TODO: rework the unsafe cast below
|
||||
PrivilegedProcess *priv = static_cast<PrivilegedProcess *>(repl);
|
||||
pd->ipcProcess.reset(priv);
|
||||
if (!pd->ipcProcess) {
|
||||
qWarning() << "Acquire PrivilegedProcess failed";
|
||||
} else {
|
||||
pd->ipcProcess->waitForSource(1000);
|
||||
if (!pd->ipcProcess->isReplicaValid()) {
|
||||
qWarning() << "PrivilegedProcess replica is not connected!";
|
||||
}
|
||||
|
||||
QObject::connect(pd->ipcProcess.data(), &PrivilegedProcess::destroyed, pd->ipcProcess.data(),
|
||||
[pd]() { pd->replicaNode->deleteLater(); });
|
||||
return withInterface([](QSharedPointer<IpcInterfaceReplica> &iface) -> QSharedPointer<IpcProcessInterfaceReplica> {
|
||||
auto createPrivilegedProcess = iface->createPrivilegedProcess();
|
||||
if (!createPrivilegedProcess.waitForFinished()) {
|
||||
qCritical() << "Failed to create privileged process";
|
||||
return nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
pd->localSocket->connectToServer(amnezia::getIpcProcessUrl(pid));
|
||||
if (!pd->localSocket->waitForConnected()) {
|
||||
qCritical() << "IpcClient::createPrivilegedProcess: Failed to connect to process' socket";
|
||||
const int pid = createPrivilegedProcess.returnValue();
|
||||
|
||||
auto* node = new QRemoteObjectNode();
|
||||
node->connectToNode(QUrl(QString("local:%1").arg(amnezia::getIpcProcessUrl(pid))));
|
||||
|
||||
QSharedPointer<IpcProcessInterfaceReplica> rep(
|
||||
node->acquire<IpcProcessInterfaceReplica>(),
|
||||
[node] (IpcProcessInterfaceReplica *ptr) {
|
||||
delete ptr;
|
||||
node->deleteLater();
|
||||
}
|
||||
);
|
||||
if (rep.isNull()) {
|
||||
qCritical() << "IpcClient::CreatePrivilegedProcess(): Failed to acquire replica";
|
||||
return nullptr;
|
||||
}
|
||||
if (!rep->waitForSource()) {
|
||||
qCritical() << "IpcClient::CreatePrivilegedProcess(): Failed to initialize replica";
|
||||
return nullptr;
|
||||
}
|
||||
if (!rep->isReplicaValid()) {
|
||||
qCritical() << "IpcClient::CreatePrivilegedProcess(): Replica is invalid";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return rep;
|
||||
},
|
||||
[]() -> QSharedPointer<IpcProcessInterfaceReplica> {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto processReplica = QSharedPointer<PrivilegedProcess>(pd->ipcProcess);
|
||||
return processReplica;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
#include <QObject>
|
||||
|
||||
#include "rep_ipc_interface_replica.h"
|
||||
#include "rep_ipc_process_tun2socks_replica.h"
|
||||
|
||||
#include "privileged_process.h"
|
||||
#include "rep_ipc_process_interface_replica.h"
|
||||
|
||||
class IpcClient : public QObject
|
||||
{
|
||||
@@ -18,8 +16,7 @@ public:
|
||||
static IpcClient& Instance();
|
||||
|
||||
static QSharedPointer<IpcInterfaceReplica> Interface();
|
||||
static QSharedPointer<IpcProcessTun2SocksReplica> InterfaceTun2Socks();
|
||||
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
|
||||
static QSharedPointer<IpcProcessInterfaceReplica> CreatePrivilegedProcess();
|
||||
|
||||
template <typename Func>
|
||||
static auto withInterface(Func func)
|
||||
@@ -54,18 +51,6 @@ signals:
|
||||
private:
|
||||
QRemoteObjectNode m_node;
|
||||
QSharedPointer<IpcInterfaceReplica> m_interface;
|
||||
QSharedPointer<IpcProcessTun2SocksReplica> m_tun2socks;
|
||||
|
||||
struct ProcessDescriptor {
|
||||
ProcessDescriptor () {
|
||||
replicaNode = QSharedPointer<QRemoteObjectNode>(new QRemoteObjectNode());
|
||||
ipcProcess = QSharedPointer<PrivilegedProcess>();
|
||||
localSocket = QSharedPointer<QLocalSocket>();
|
||||
}
|
||||
QSharedPointer<PrivilegedProcess> ipcProcess;
|
||||
QSharedPointer<QRemoteObjectNode> replicaNode;
|
||||
QSharedPointer<QLocalSocket> localSocket;
|
||||
};
|
||||
};
|
||||
|
||||
#endif // IPCCLIENT_H
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#include "privileged_process.h"
|
||||
|
||||
PrivilegedProcess::PrivilegedProcess() :
|
||||
IpcProcessInterfaceReplica()
|
||||
{
|
||||
}
|
||||
|
||||
PrivilegedProcess::~PrivilegedProcess()
|
||||
{
|
||||
qDebug() << "PrivilegedProcess::~PrivilegedProcess()";
|
||||
}
|
||||
|
||||
void PrivilegedProcess::waitForFinished(int msecs)
|
||||
{
|
||||
QSharedPointer<QEventLoop> loop(new QEventLoop);
|
||||
connect(this, &PrivilegedProcess::finished, this, [this, loop](int exitCode, QProcess::ExitStatus exitStatus) mutable{
|
||||
loop->quit();
|
||||
loop.clear();
|
||||
});
|
||||
|
||||
QTimer::singleShot(msecs, this, [this, loop]() mutable {
|
||||
loop->quit();
|
||||
loop.clear();
|
||||
});
|
||||
|
||||
loop->exec();
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifndef PRIVILEGED_PROCESS_H
|
||||
#define PRIVILEGED_PROCESS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "rep_ipc_process_interface_replica.h"
|
||||
// This class is dangerous - instance of this class casted from base class,
|
||||
// so it support only functions
|
||||
// Do not add any members into it
|
||||
//
|
||||
class PrivilegedProcess : public IpcProcessInterfaceReplica
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PrivilegedProcess();
|
||||
~PrivilegedProcess() override;
|
||||
|
||||
void waitForFinished(int msecs);
|
||||
|
||||
};
|
||||
|
||||
#endif // PRIVILEGED_PROCESS_H
|
||||
|
||||
|
||||
@@ -110,21 +110,14 @@ set_property(TARGET networkextension APPEND PROPERTY RESOURCE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
|
||||
)
|
||||
|
||||
## Build wireguard-go-version.h
|
||||
execute_process(
|
||||
COMMAND go list -m golang.zx2c4.com/wireguard
|
||||
WORKING_DIRECTORY ${CLIENT_ROOT_DIR}/3rd/wireguard-apple/Sources/WireGuardKitGo
|
||||
OUTPUT_VARIABLE WG_VERSION_FULL
|
||||
)
|
||||
string(REGEX REPLACE ".*v\([0-9.]*\).*" "\\1" WG_VERSION_STRING 1.1.1)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/wireguard-go-version.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h)
|
||||
target_sources(networkextension PRIVATE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h)
|
||||
|
||||
target_include_directories(networkextension PRIVATE ${CLIENT_ROOT_DIR})
|
||||
target_include_directories(networkextension PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
target_link_libraries(networkextension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/ios/arm64/libwg-go.a)
|
||||
find_package(openvpnadapter REQUIRED)
|
||||
target_link_libraries(networkextension PRIVATE amnezia::openvpnadapter)
|
||||
|
||||
target_link_libraries(networkextension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework)
|
||||
find_package(awg-apple REQUIRED)
|
||||
target_link_libraries(networkextension PRIVATE amnezia::awg-apple)
|
||||
|
||||
find_package(hev-socks5-tunnel REQUIRED)
|
||||
target_link_libraries(networkextension PRIVATE heiher::hev-socks5-tunnel)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#ifndef WIREGUARD_GO_VERSION
|
||||
#define WIREGUARD_GO_VERSION "@WG_VERSION_STRING@"
|
||||
#endif // WIREGUARD_GO_VERSION
|
||||
@@ -114,25 +114,14 @@ set_property(TARGET AmneziaVPNNetworkExtension APPEND PROPERTY RESOURCE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/PrivacyInfo.xcprivacy
|
||||
)
|
||||
|
||||
## Build wireguard-go-version.h
|
||||
execute_process(
|
||||
COMMAND go list -m golang.zx2c4.com/wireguard
|
||||
WORKING_DIRECTORY ${CLIENT_ROOT_DIR}/3rd/wireguard-apple/Sources/WireGuardKitGo
|
||||
OUTPUT_VARIABLE WG_VERSION_FULL
|
||||
)
|
||||
string(REGEX REPLACE ".*v\([0-9.]*\).*" "\\1" WG_VERSION_STRING 1.1.1)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/wireguard-go-version.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h)
|
||||
target_sources(AmneziaVPNNetworkExtension PRIVATE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wireguard-go-version.h)
|
||||
|
||||
target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR})
|
||||
target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/wireguard/macos/universal2/libwg-go.a)
|
||||
find_package(openvpnadapter REQUIRED)
|
||||
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE amnezia::openvpnadapter)
|
||||
|
||||
message(${CLIENT_ROOT_DIR})
|
||||
message(${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/libhev-socks5-tunnel.a)
|
||||
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/libhev-socks5-tunnel.a)
|
||||
find_package(awg-apple REQUIRED)
|
||||
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE amnezia::awg-apple)
|
||||
|
||||
target_include_directories(AmneziaVPNNetworkExtension PRIVATE ${CLIENT_ROOT_DIR}/3rd-prebuilt/3rd-prebuilt/xray/HevSocks5Tunnel.xcframework/macos-arm64_x86_64/Headers)
|
||||
find_package(hev-socks5-tunnel REQUIRED)
|
||||
target_link_libraries(AmneziaVPNNetworkExtension PRIVATE heiher::hev-socks5-tunnel)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#ifndef WIREGUARD_GO_VERSION
|
||||
#define WIREGUARD_GO_VERSION "@WG_VERSION_STRING@"
|
||||
#endif // WIREGUARD_GO_VERSION
|
||||
@@ -75,7 +75,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
qInfo().noquote() << QString("Started %1 version %2 %3").arg(APPLICATION_NAME, APP_VERSION, GIT_COMMIT_HASH);
|
||||
qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture());
|
||||
qInfo().noquote() << QString("SSL backend: %1").arg(QSslSocket::sslLibraryVersionString());
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@@ -72,9 +72,9 @@ void NetworkWatcher::initialize() {
|
||||
connect(m_impl, &NetworkWatcherImpl::unsecuredNetwork, this,
|
||||
&NetworkWatcher::unsecuredNetwork);
|
||||
connect(m_impl, &NetworkWatcherImpl::networkChanged, this,
|
||||
&NetworkWatcher::networkChange);
|
||||
connect(m_impl, &NetworkWatcherImpl::sleepMode, this,
|
||||
&NetworkWatcher::onSleepMode);
|
||||
&NetworkWatcher::networkChanged);
|
||||
connect(m_impl, &NetworkWatcherImpl::wakeup, this,
|
||||
&NetworkWatcher::wakeup);
|
||||
m_impl->initialize();
|
||||
|
||||
// Enable sleep/wake monitoring for VPN auto-reconnection
|
||||
@@ -97,12 +97,6 @@ void NetworkWatcher::settingsChanged() {
|
||||
logger.debug() << "NetworkWatcher settings changed - keeping sleep monitoring active";
|
||||
}
|
||||
|
||||
void NetworkWatcher::onSleepMode()
|
||||
{
|
||||
logger.debug() << "Resumed from sleep mode";
|
||||
emit sleepMode();
|
||||
}
|
||||
|
||||
void NetworkWatcher::unsecuredNetwork(const QString& networkName,
|
||||
const QString& networkId) {
|
||||
logger.debug() << "Unsecured network:" << logger.sensitive(networkName)
|
||||
|
||||
@@ -29,13 +29,11 @@ public:
|
||||
// false to restore.
|
||||
void simulateDisconnection(bool simulatedDisconnection);
|
||||
|
||||
void onSleepMode();
|
||||
|
||||
QNetworkInformation::Reachability getReachability();
|
||||
|
||||
signals:
|
||||
void networkChange();
|
||||
void sleepMode();
|
||||
void networkChanged();
|
||||
void wakeup();
|
||||
|
||||
private:
|
||||
void settingsChanged();
|
||||
|
||||
@@ -41,7 +41,7 @@ signals:
|
||||
// TODO: Only windows-networkwatcher has this, the other plattforms should
|
||||
// too.
|
||||
void networkChanged(QString newBSSID);
|
||||
void sleepMode();
|
||||
void wakeup();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@@ -80,7 +80,7 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) {
|
||||
|
||||
QDir appPath(QCoreApplication::applicationDirPath());
|
||||
QStringList wgArgs = {"-f", "amn0"};
|
||||
m_tunnel.start(appPath.filePath("../../client/bin/wireguard-go"), wgArgs);
|
||||
m_tunnel.start(appPath.filePath("../../client/bin/amneziawg-go"), wgArgs);
|
||||
if (!m_tunnel.waitForStarted(WG_TUN_PROC_TIMEOUT)) {
|
||||
logger.error() << "Unable to start tunnel process due to timeout";
|
||||
m_tunnel.kill();
|
||||
|
||||
@@ -41,8 +41,8 @@ void LinuxNetworkWatcher::initialize() {
|
||||
connect(m_worker, &LinuxNetworkWatcherWorker::unsecuredNetwork, this,
|
||||
&LinuxNetworkWatcher::unsecuredNetwork);
|
||||
|
||||
connect(m_worker, &LinuxNetworkWatcherWorker::sleepMode, this,
|
||||
&NetworkWatcherImpl::sleepMode);
|
||||
connect(m_worker, &LinuxNetworkWatcherWorker::wakeup, this,
|
||||
&NetworkWatcherImpl::wakeup);
|
||||
|
||||
// Let's wait a few seconds to allow the UI to be fully loaded and shown.
|
||||
// This is not strictly needed, but it's better for user experience because
|
||||
|
||||
@@ -200,7 +200,7 @@ void LinuxNetworkWatcherWorker::checkDevices() {
|
||||
void LinuxNetworkWatcherWorker::NMStateChanged(quint32 state)
|
||||
{
|
||||
if (state == NM_STATE_ASLEEP) {
|
||||
emit sleepMode();
|
||||
emit wakeup();
|
||||
}
|
||||
|
||||
logger.debug() << "NMStateChanged " << state;
|
||||
|
||||
@@ -23,7 +23,7 @@ class LinuxNetworkWatcherWorker final : public QObject {
|
||||
|
||||
signals:
|
||||
void unsecuredNetwork(const QString& networkName, const QString& networkId);
|
||||
void sleepMode();
|
||||
void wakeup();
|
||||
|
||||
public slots:
|
||||
void initialize();
|
||||
|
||||
@@ -79,7 +79,7 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) {
|
||||
|
||||
QDir appPath(QCoreApplication::applicationDirPath());
|
||||
QStringList wgArgs = {"-f", "utun"};
|
||||
m_tunnel.start(appPath.filePath("wireguard-go"), wgArgs);
|
||||
m_tunnel.start(appPath.filePath("amneziawg-go"), wgArgs);
|
||||
if (!m_tunnel.waitForStarted(WG_TUN_PROC_TIMEOUT)) {
|
||||
logger.error() << "Unable to start tunnel process due to timeout";
|
||||
m_tunnel.kill();
|
||||
|
||||
@@ -173,10 +173,10 @@ void PowerNotificationsListener::sleepWakeupCallBack(void *refParam, io_service_
|
||||
|
||||
case kIOMessageSystemHasPoweredOn:
|
||||
/* Announces that the system and its devices have woken up. */
|
||||
logger.debug() << "System has powered on - emitting sleepMode signal from dedicated CFRunLoop thread";
|
||||
logger.debug() << "System has powered on - emitting wakeup signal from dedicated CFRunLoop thread";
|
||||
if (listener->m_watcher) {
|
||||
// Use QMetaObject::invokeMethod for thread-safe signal emission
|
||||
QMetaObject::invokeMethod(listener->m_watcher, "sleepMode", Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(listener->m_watcher, "wakeup", Qt::QueuedConnection);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -62,6 +62,9 @@ void WindowsDaemon::prepareActivation(const InterfaceConfig& config, int inetAda
|
||||
}
|
||||
|
||||
void WindowsDaemon::activateSplitTunnel(const InterfaceConfig& config, int vpnAdapterIndex) {
|
||||
if (m_splitTunnelManager == nullptr)
|
||||
return;
|
||||
|
||||
if (config.m_vpnDisabledApps.length() > 0) {
|
||||
m_splitTunnelManager->start(m_inetAdapterIndex, vpnAdapterIndex);
|
||||
m_splitTunnelManager->excludeApps(config.m_vpnDisabledApps);
|
||||
|
||||
@@ -41,7 +41,7 @@ LRESULT WindowsNetworkWatcher::PowerWndProcCallback(HWND hwnd, UINT uMsg, WPARAM
|
||||
switch (uMsg) {
|
||||
case WM_POWERBROADCAST:
|
||||
if (wParam == PBT_APMRESUMESUSPEND) {
|
||||
emit obj->sleepMode();
|
||||
emit obj->wakeup();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -232,12 +232,6 @@ ErrorCode OpenVpnProtocol::start()
|
||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
}
|
||||
|
||||
m_openVpnProcess->waitForSource(5000);
|
||||
if (!m_openVpnProcess->isInitialized()) {
|
||||
qWarning() << "IpcProcess replica is not connected!";
|
||||
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
}
|
||||
m_openVpnProcess->setProgram(PermittedProcess::OpenVPN);
|
||||
QStringList arguments({
|
||||
"--config", configPath(), "--management", m_managementHost, QString::number(mgmtPort),
|
||||
@@ -246,13 +240,13 @@ ErrorCode OpenVpnProtocol::start()
|
||||
m_openVpnProcess->setArguments(arguments);
|
||||
|
||||
qDebug() << arguments.join(" ");
|
||||
connect(m_openVpnProcess.data(), &PrivilegedProcess::errorOccurred,
|
||||
connect(m_openVpnProcess.data(), &IpcProcessInterfaceReplica::errorOccurred,
|
||||
[&](QProcess::ProcessError error) { qDebug() << "PrivilegedProcess errorOccurred" << error; });
|
||||
|
||||
connect(m_openVpnProcess.data(), &PrivilegedProcess::stateChanged,
|
||||
connect(m_openVpnProcess.data(), &IpcProcessInterfaceReplica::stateChanged,
|
||||
[&](QProcess::ProcessState newState) { qDebug() << "PrivilegedProcess stateChanged" << newState; });
|
||||
|
||||
connect(m_openVpnProcess.data(), &PrivilegedProcess::finished, this,
|
||||
connect(m_openVpnProcess.data(), &IpcProcessInterfaceReplica::finished, this,
|
||||
[&]() { setConnectionState(Vpn::ConnectionState::Disconnected); });
|
||||
|
||||
m_openVpnProcess->start();
|
||||
|
||||
@@ -53,7 +53,7 @@ private:
|
||||
void updateRouteGateway(QString line);
|
||||
void updateVpnGateway(const QString &line);
|
||||
|
||||
QSharedPointer<PrivilegedProcess> m_openVpnProcess;
|
||||
QSharedPointer<IpcProcessInterfaceReplica> m_openVpnProcess;
|
||||
};
|
||||
|
||||
#endif // OPENVPNPROTOCOL_H
|
||||
|
||||
@@ -233,7 +233,7 @@ namespace amnezia
|
||||
constexpr char defaultResponsePacketMagicHeader[] = "3288052141";
|
||||
constexpr char defaultTransportPacketMagicHeader[] = "2528465083";
|
||||
constexpr char defaultUnderloadPacketMagicHeader[] = "1766607858";
|
||||
constexpr char defaultSpecialJunk1[] = "<b 0x084481800001000300000000077469636b65747306776964676574096b696e6f706f69736b0272750000010001c00c0005000100000039001806776964676574077469636b6574730679616e646578c025c0390005000100000039002b1765787465726e616c2d7469636b6574732d776964676574066166697368610679616e646578036e657400c05d000100010000001c000457fafe25>";
|
||||
constexpr char defaultSpecialJunk1[] = "<r 2><b 0x858000010001000000000669636c6f756403636f6d0000010001c00c000100010000105a00044d583737>";
|
||||
constexpr char defaultSpecialJunk2[] = "";
|
||||
constexpr char defaultSpecialJunk3[] = "";
|
||||
constexpr char defaultSpecialJunk4[] = "";
|
||||
|
||||
@@ -15,7 +15,7 @@ WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject *
|
||||
m_impl.reset(new LocalSocketController());
|
||||
connect(m_impl.get(), &ControllerImpl::connected, this,
|
||||
[this](const QString &pubkey, const QDateTime &connectionTimestamp) {
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Connected);
|
||||
setConnectionState(Vpn::ConnectionState::Connected);
|
||||
});
|
||||
connect(m_impl.get(), &ControllerImpl::statusUpdated, this,
|
||||
[this](const QString& serverIpv4Gateway,
|
||||
@@ -38,7 +38,7 @@ WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject *
|
||||
});
|
||||
|
||||
connect(m_impl.get(), &ControllerImpl::disconnected, this,
|
||||
[this]() { emit connectionStateChanged(Vpn::ConnectionState::Disconnected); });
|
||||
[this]() { setConnectionState(Vpn::ConnectionState::Disconnected); });
|
||||
m_impl->initialize(nullptr, nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "xrayprotocol.h"
|
||||
|
||||
#include "core/ipcclient.h"
|
||||
#include "ipc.h"
|
||||
#include "utilities.h"
|
||||
#include "core/networkUtilities.h"
|
||||
|
||||
@@ -9,14 +10,37 @@
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkInterface>
|
||||
#include <QJsonDocument>
|
||||
#include <QtCore/qlogging.h>
|
||||
#include <QtCore/qobjectdefs.h>
|
||||
#include <QtCore/qprocess.h>
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
static const QString tunName = "utun22";
|
||||
#else
|
||||
static const QString tunName = "tun2";
|
||||
#endif
|
||||
|
||||
XrayProtocol::XrayProtocol(const QJsonObject &configuration, QObject *parent) : VpnProtocol(configuration, parent)
|
||||
{
|
||||
readXrayConfiguration(configuration);
|
||||
m_routeGateway = NetworkUtilities::getGatewayAndIface().first;
|
||||
m_vpnGateway = amnezia::protocols::xray::defaultLocalAddr;
|
||||
m_vpnLocalAddress = amnezia::protocols::xray::defaultLocalAddr;
|
||||
m_t2sProcess = IpcClient::InterfaceTun2Socks();
|
||||
m_routeGateway = NetworkUtilities::getGatewayAndIface().first;
|
||||
|
||||
m_routeMode = static_cast<Settings::RouteMode>(configuration.value(amnezia::config_key::splitTunnelType).toInt());
|
||||
m_remoteAddress = NetworkUtilities::getIPAddress(m_rawConfig.value(amnezia::config_key::hostName).toString());
|
||||
|
||||
const QString primaryDns = configuration.value(amnezia::config_key::dns1).toString();
|
||||
m_dnsServers.push_back(QHostAddress(primaryDns));
|
||||
if (primaryDns != amnezia::protocols::dns::amneziaDnsIp) {
|
||||
const QString secondaryDns = configuration.value(amnezia::config_key::dns2).toString();
|
||||
m_dnsServers.push_back(QHostAddress(secondaryDns));
|
||||
}
|
||||
|
||||
QJsonObject xrayConfiguration = configuration.value(ProtocolProps::key_proto_config_data(Proto::Xray)).toObject();
|
||||
if (xrayConfiguration.isEmpty()) {
|
||||
xrayConfiguration = configuration.value(ProtocolProps::key_proto_config_data(Proto::SSXray)).toObject();
|
||||
}
|
||||
m_xrayConfig = xrayConfiguration;
|
||||
}
|
||||
|
||||
XrayProtocol::~XrayProtocol()
|
||||
@@ -29,106 +53,16 @@ ErrorCode XrayProtocol::start()
|
||||
{
|
||||
qDebug() << "XrayProtocol::start()";
|
||||
|
||||
const ErrorCode err = IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
iface->xrayStart(QJsonDocument(m_xrayConfig).toJson());
|
||||
return ErrorCode::NoError;
|
||||
return IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
auto xrayStart = iface->xrayStart(QJsonDocument(m_xrayConfig).toJson());
|
||||
if (!xrayStart.waitForFinished() || !xrayStart.returnValue()) {
|
||||
qCritical() << "Failed to start xray";
|
||||
return ErrorCode::XrayExecutableCrashed;
|
||||
}
|
||||
return startTun2Socks();
|
||||
}, [] () {
|
||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
});
|
||||
if (err != ErrorCode::NoError)
|
||||
return err;
|
||||
|
||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||
return startTun2Sock();
|
||||
}
|
||||
|
||||
ErrorCode XrayProtocol::setupRouting() {
|
||||
return IpcClient::withInterface([this](QSharedPointer<IpcInterfaceReplica> iface) -> ErrorCode {
|
||||
QList<QHostAddress> dnsAddr;
|
||||
|
||||
dnsAddr.push_back(QHostAddress(m_primaryDNS));
|
||||
// We don't use secondary DNS if primary DNS is AmneziaDNS
|
||||
if (!m_primaryDNS.contains(amnezia::protocols::dns::amneziaDnsIp)) {
|
||||
dnsAddr.push_back(QHostAddress(m_secondaryDNS));
|
||||
}
|
||||
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
#ifdef Q_OS_MACOS
|
||||
const QString tunName = "utun22";
|
||||
#else
|
||||
const QString tunName = "tun2";
|
||||
#endif
|
||||
auto createTun = iface->createTun(tunName, amnezia::protocols::xray::defaultLocalAddr);
|
||||
if (!createTun.waitForFinished(1000) || !createTun.returnValue()) {
|
||||
qWarning() << "Failed to assign IP address for TUN";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
auto updateResolvers = iface->updateResolvers(tunName, dnsAddr);
|
||||
if (!updateResolvers.waitForFinished(1000) || !updateResolvers.returnValue()) {
|
||||
qWarning() << "Failed to set DNS resolvers for TUN";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_routeMode == Settings::RouteMode::VpnAllSites) {
|
||||
static const QStringList subnets = { "1.0.0.0/8", "2.0.0.0/7", "4.0.0.0/6", "8.0.0.0/5", "16.0.0.0/4", "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/1" };
|
||||
|
||||
auto routeAddList = iface->routeAddList(m_vpnGateway, subnets);
|
||||
if (!routeAddList.waitForFinished(1000) || routeAddList.returnValue() != subnets.count()) {
|
||||
qWarning() << "Failed to set routes for TUN";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
}
|
||||
|
||||
auto StopRoutingIpv6 = iface->StopRoutingIpv6();
|
||||
if (!StopRoutingIpv6.waitForFinished(1000) || !StopRoutingIpv6.returnValue()) {
|
||||
qWarning() << "Failed to disable IPv6 routing";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
auto enablePeerTraffic = iface->enablePeerTraffic(m_xrayConfig);
|
||||
if (!enablePeerTraffic.waitForFinished(5000) || !enablePeerTraffic.returnValue()) {
|
||||
qWarning() << "Failed to enable peer traffic";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
#endif
|
||||
return ErrorCode::NoError;
|
||||
},
|
||||
[] () {
|
||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
});
|
||||
}
|
||||
|
||||
ErrorCode XrayProtocol::startTun2Sock()
|
||||
{
|
||||
m_t2sProcess->start();
|
||||
|
||||
connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::stateChanged, this,
|
||||
[&](QProcess::ProcessState newState) { qDebug() << "PrivilegedProcess stateChanged" << newState; });
|
||||
|
||||
connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::setConnectionState, this, [&](int vpnState) {
|
||||
QMetaObject::invokeMethod(this, [this, vpnState]() {
|
||||
qDebug() << "PrivilegedProcess setConnectionState " << vpnState;
|
||||
|
||||
if (vpnState == Vpn::ConnectionState::Connected) {
|
||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||
|
||||
if (ErrorCode res = setupRouting(); res != ErrorCode::NoError) {
|
||||
stop();
|
||||
setLastError(res);
|
||||
} else
|
||||
setConnectionState(Vpn::ConnectionState::Connected);
|
||||
}
|
||||
|
||||
if (vpnState == Vpn::ConnectionState::Disconnected)
|
||||
stop();
|
||||
|
||||
}, Qt::QueuedConnection);
|
||||
});
|
||||
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
void XrayProtocol::stop()
|
||||
@@ -136,43 +70,177 @@ void XrayProtocol::stop()
|
||||
qDebug() << "XrayProtocol::stop()";
|
||||
|
||||
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
auto disableKillSwitch = iface->disableKillSwitch();
|
||||
if (!disableKillSwitch.waitForFinished() || !disableKillSwitch.returnValue())
|
||||
qWarning() << "Failed to disable killswitch";
|
||||
|
||||
auto StartRoutingIpv6 = iface->StartRoutingIpv6();
|
||||
if (!StartRoutingIpv6.waitForFinished(1000) || !StartRoutingIpv6.returnValue()) {
|
||||
qWarning() << "XrayProtocol::stop(): Failed to start routing ipv6";
|
||||
}
|
||||
if (!StartRoutingIpv6.waitForFinished() || !StartRoutingIpv6.returnValue())
|
||||
qWarning() << "Failed to start routing ipv6";
|
||||
|
||||
auto restoreResolvers = iface->restoreResolvers();
|
||||
if (!restoreResolvers.waitForFinished(1000) || !restoreResolvers.returnValue()) {
|
||||
qWarning() << "XrayProtocol::stop(): Failed to restore resolvers";
|
||||
}
|
||||
if (!restoreResolvers.waitForFinished() || !restoreResolvers.returnValue())
|
||||
qWarning() << "Failed to restore resolvers";
|
||||
|
||||
#if !defined(Q_OS_MACOS)
|
||||
auto deleteTun = iface->deleteTun("tun2");
|
||||
if (!deleteTun.waitForFinished(1000) || !deleteTun.returnValue()) {
|
||||
qWarning() << "XrayProtocol::stop(): Failed to delete tun";
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
iface->xrayStop();
|
||||
auto deleteTun = iface->deleteTun(tunName);
|
||||
if (!deleteTun.waitForFinished() || !deleteTun.returnValue())
|
||||
qWarning() << "Failed to delete tun";
|
||||
|
||||
auto xrayStop = iface->xrayStop();
|
||||
if (!xrayStop.waitForFinished() || !xrayStop.returnValue())
|
||||
qWarning() << "Failed to stop xray";
|
||||
});
|
||||
|
||||
if (m_t2sProcess) {
|
||||
m_t2sProcess->stop();
|
||||
QThread::msleep(200);
|
||||
if (m_tun2socksProcess) {
|
||||
m_tun2socksProcess->blockSignals(true);
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
m_tun2socksProcess->terminate();
|
||||
auto waitForFinished = m_tun2socksProcess->waitForFinished(1000);
|
||||
if (!waitForFinished.waitForFinished() || !waitForFinished.returnValue()) {
|
||||
qWarning() << "Failed to terminate tun2socks. Killing the process...";
|
||||
m_tun2socksProcess->kill();
|
||||
}
|
||||
#else
|
||||
// terminate does not do anything useful on Windows
|
||||
// so just kill the process
|
||||
m_tun2socksProcess->kill();
|
||||
#endif
|
||||
|
||||
m_tun2socksProcess->close();
|
||||
m_tun2socksProcess.reset();
|
||||
}
|
||||
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
}
|
||||
|
||||
void XrayProtocol::readXrayConfiguration(const QJsonObject &configuration)
|
||||
ErrorCode XrayProtocol::startTun2Socks()
|
||||
{
|
||||
QJsonObject xrayConfiguration = configuration.value(ProtocolProps::key_proto_config_data(Proto::Xray)).toObject();
|
||||
if (xrayConfiguration.isEmpty()) {
|
||||
xrayConfiguration = configuration.value(ProtocolProps::key_proto_config_data(Proto::SSXray)).toObject();
|
||||
m_tun2socksProcess = IpcClient::CreatePrivilegedProcess();
|
||||
if (!m_tun2socksProcess->waitForSource()) {
|
||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
}
|
||||
m_xrayConfig = xrayConfiguration;
|
||||
m_routeMode = static_cast<Settings::RouteMode>(configuration.value(amnezia::config_key::splitTunnelType).toInt());
|
||||
m_primaryDNS = configuration.value(amnezia::config_key::dns1).toString();
|
||||
m_secondaryDNS = configuration.value(amnezia::config_key::dns2).toString();
|
||||
|
||||
m_tun2socksProcess->setProgram(PermittedProcess::Tun2Socks);
|
||||
m_tun2socksProcess->setArguments({"-device", QString("tun://%1").arg(tunName), "-proxy", "socks5://127.0.0.1:10808" });
|
||||
|
||||
connect(m_tun2socksProcess.data(), &IpcProcessInterfaceReplica::readyReadStandardError, this, [this]() {
|
||||
auto readAllStandardError = m_tun2socksProcess->readAllStandardError();
|
||||
if (!readAllStandardError.waitForFinished()) {
|
||||
qWarning() << "Failed to read output from tun2socks";
|
||||
return;
|
||||
}
|
||||
|
||||
const QString line = readAllStandardError.returnValue();
|
||||
|
||||
if (!line.contains("[TCP]") && !line.contains("[UDP]"))
|
||||
qDebug() << "[tun2socks]:" << line;
|
||||
|
||||
if (line.contains("[STACK] tun://") && line.contains("<-> socks5://127.0.0.1")) {
|
||||
disconnect(m_tun2socksProcess.data(), &IpcProcessInterfaceReplica::readyReadStandardOutput, this, nullptr);
|
||||
|
||||
if (ErrorCode res = setupRouting(); res != ErrorCode::NoError) {
|
||||
stop();
|
||||
setLastError(res);
|
||||
} else {
|
||||
setConnectionState(Vpn::ConnectionState::Connected);
|
||||
}
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
connect(m_tun2socksProcess.data(), &IpcProcessInterfaceReplica::finished, this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
if (exitStatus == QProcess::ExitStatus::CrashExit) {
|
||||
qCritical() << "Tun2socks process crashed!";
|
||||
} else {
|
||||
qCritical() << QString("Tun2socks process was closed with %1 exit code").arg(exitCode);
|
||||
}
|
||||
stop();
|
||||
setLastError(ErrorCode::Tun2SockExecutableCrashed);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
m_tun2socksProcess->start();
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
ErrorCode XrayProtocol::setupRouting() {
|
||||
return IpcClient::withInterface([this](QSharedPointer<IpcInterfaceReplica> iface) -> ErrorCode {
|
||||
#ifdef Q_OS_WIN
|
||||
const int inetAdapterIndex = NetworkUtilities::AdapterIndexTo(QHostAddress(m_remoteAddress));
|
||||
#endif
|
||||
auto createTun = iface->createTun(tunName, amnezia::protocols::xray::defaultLocalAddr);
|
||||
if (!createTun.waitForFinished() || !createTun.returnValue()) {
|
||||
qCritical() << "Failed to assign IP address for TUN";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
auto updateResolvers = iface->updateResolvers(tunName, m_dnsServers);
|
||||
if (!updateResolvers.waitForFinished() || !updateResolvers.returnValue()) {
|
||||
qCritical() << "Failed to set DNS resolvers for TUN";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
int vpnAdapterIndex = -1;
|
||||
QList<QNetworkInterface> netInterfaces = QNetworkInterface::allInterfaces();
|
||||
for (auto& netInterface : netInterfaces) {
|
||||
for (auto& address : netInterface.addressEntries()) {
|
||||
if (m_vpnLocalAddress == address.ip().toString())
|
||||
vpnAdapterIndex = netInterface.index();
|
||||
}
|
||||
}
|
||||
#else
|
||||
static const int vpnAdapterIndex = 0;
|
||||
#endif
|
||||
const bool killSwitchEnabled = QVariant(m_rawConfig.value(config_key::killSwitchOption).toString()).toBool();
|
||||
if (killSwitchEnabled) {
|
||||
if (vpnAdapterIndex != -1) {
|
||||
QJsonObject config = m_rawConfig;
|
||||
config.insert("vpnServer", m_remoteAddress);
|
||||
|
||||
auto enableKillSwitch = IpcClient::Interface()->enableKillSwitch(config, vpnAdapterIndex);
|
||||
if (!enableKillSwitch.waitForFinished() || !enableKillSwitch.returnValue()) {
|
||||
qCritical() << "Failed to enable killswitch";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
} else
|
||||
qWarning() << "Failed to get vpnAdapterIndex. Killswitch disabled";
|
||||
}
|
||||
|
||||
if (m_routeMode == Settings::RouteMode::VpnAllSites) {
|
||||
static const QStringList subnets = { "1.0.0.0/8", "2.0.0.0/7", "4.0.0.0/6", "8.0.0.0/5", "16.0.0.0/4", "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/1" };
|
||||
|
||||
auto routeAddList = iface->routeAddList(m_vpnGateway, subnets);
|
||||
if (!routeAddList.waitForFinished() || routeAddList.returnValue() != subnets.count()) {
|
||||
qCritical() << "Failed to set routes for TUN";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
}
|
||||
|
||||
auto StopRoutingIpv6 = iface->StopRoutingIpv6();
|
||||
if (!StopRoutingIpv6.waitForFinished() || !StopRoutingIpv6.returnValue()) {
|
||||
qCritical() << "Failed to disable IPv6 routing";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (inetAdapterIndex != -1 && vpnAdapterIndex != -1) {
|
||||
QJsonObject config = m_rawConfig;
|
||||
config.insert("inetAdapterIndex", inetAdapterIndex);
|
||||
config.insert("vpnAdapterIndex", vpnAdapterIndex);
|
||||
config.insert("vpnGateway", m_vpnGateway);
|
||||
config.insert("vpnServer", m_remoteAddress);
|
||||
|
||||
auto enablePeerTraffic = iface->enablePeerTraffic(config);
|
||||
if (!enablePeerTraffic.waitForFinished() || !enablePeerTraffic.returnValue()) {
|
||||
qCritical() << "Failed to enable peer traffic";
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
} else
|
||||
qWarning() << "Failed to get adapter indexes. Split-tunneling disabled";
|
||||
#endif
|
||||
return ErrorCode::NoError;
|
||||
},
|
||||
[] () {
|
||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "core/ipcclient.h"
|
||||
#include "vpnprotocol.h"
|
||||
#include "settings.h"
|
||||
#include <QtCore/qsharedpointer.h>
|
||||
|
||||
class XrayProtocol : public VpnProtocol
|
||||
{
|
||||
@@ -18,16 +19,14 @@ public:
|
||||
|
||||
private:
|
||||
ErrorCode setupRouting();
|
||||
ErrorCode startTun2Sock();
|
||||
void readXrayConfiguration(const QJsonObject &configuration);
|
||||
|
||||
ErrorCode startTun2Socks();
|
||||
|
||||
QJsonObject m_xrayConfig;
|
||||
Settings::RouteMode m_routeMode;
|
||||
QString m_primaryDNS;
|
||||
QString m_secondaryDNS;
|
||||
#ifndef Q_OS_IOS
|
||||
QSharedPointer<IpcProcessTun2SocksReplica> m_t2sProcess;
|
||||
#endif
|
||||
QList<QHostAddress> m_dnsServers;
|
||||
QString m_remoteAddress;
|
||||
|
||||
QSharedPointer<IpcProcessInterfaceReplica> m_tun2socksProcess;
|
||||
};
|
||||
|
||||
#endif // XRAYPROTOCOL_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -291,6 +291,8 @@ void ImportController::processNativeWireGuardConfig()
|
||||
clientProtocolConfig[config_key::cookieReplyPacketJunkSize] = "0";
|
||||
clientProtocolConfig[config_key::transportPacketJunkSize] = "0";
|
||||
|
||||
clientProtocolConfig[config_key::specialJunk1] = protocols::awg::defaultSpecialJunk1;
|
||||
|
||||
clientProtocolConfig[config_key::isObfuscationEnabled] = true;
|
||||
|
||||
serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson());
|
||||
|
||||
@@ -158,7 +158,6 @@ void SettingsController::clearLogs()
|
||||
|
||||
qInfo().noquote() << QString("Started %1 version %2 %3").arg(APPLICATION_NAME, APP_VERSION, GIT_COMMIT_HASH);
|
||||
qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture());
|
||||
qInfo().noquote() << QString("SSL backend: %1").arg(QSslSocket::sslLibraryVersionString());
|
||||
}
|
||||
|
||||
void SettingsController::backupAppConfig(const QString &fileName)
|
||||
|
||||
@@ -396,9 +396,7 @@ PageType {
|
||||
PageController.showNotificationMessage(qsTr("Cannot remove server during active connection"))
|
||||
} else {
|
||||
PageController.showBusyIndicator(true)
|
||||
if (ApiConfigsController.deactivateDevice(true)) {
|
||||
InstallController.removeProcessedServer()
|
||||
}
|
||||
InstallController.removeProcessedServer()
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ VpnConnection::VpnConnection(std::shared_ptr<Settings> settings, QObject *parent
|
||||
m_checkTimer.setInterval(1000);
|
||||
connect(IosController::Instance(), &IosController::connectionStateChanged, this, &VpnConnection::onConnectionStateChanged);
|
||||
connect(IosController::Instance(), &IosController::bytesChanged, this, &VpnConnection::onBytesChanged);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -59,7 +58,7 @@ void VpnConnection::onKillSwitchModeChanged(bool enabled)
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
IpcClient::withInterface([enabled](QSharedPointer<IpcInterfaceReplica> iface){
|
||||
QRemoteObjectPendingReply<bool> reply = iface->refreshKillSwitch(enabled);
|
||||
if (reply.waitForFinished(1000) && reply.returnValue())
|
||||
if (reply.waitForFinished() && reply.returnValue())
|
||||
qDebug() << "VpnConnection::onKillSwitchModeChanged: Killswitch refreshed";
|
||||
else
|
||||
qWarning() << "VpnConnection::onKillSwitchModeChanged: Failed to execute remote refreshKillSwitch call";
|
||||
@@ -73,60 +72,57 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
auto container = m_settings->defaultContainer(m_settings->defaultServerIndex());
|
||||
|
||||
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
if (state == Vpn::ConnectionState::Connected) {
|
||||
iface->resetIpStack();
|
||||
iface->flushDns();
|
||||
switch (state) {
|
||||
case Vpn::ConnectionState::Connected: {
|
||||
iface->resetIpStack();
|
||||
|
||||
if (!ContainerProps::isAwgContainer(container) &&
|
||||
container != DockerContainer::WireGuard) {
|
||||
QString dns1 = m_vpnConfiguration.value(config_key::dns1).toString();
|
||||
QString dns2 = m_vpnConfiguration.value(config_key::dns2).toString();
|
||||
auto flushDns = iface->flushDns();
|
||||
if (flushDns.waitForFinished() && flushDns.returnValue())
|
||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully flushed DNS";
|
||||
else
|
||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to clear saved routes";
|
||||
|
||||
iface->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << dns1 << dns2);
|
||||
|
||||
if (m_settings->isSitesSplitTunnelingEnabled()) {
|
||||
iface->routeDeleteList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0");
|
||||
// qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << forwardIps.size();
|
||||
if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
|
||||
QTimer::singleShot(1000, m_vpnProtocol.data(),
|
||||
[this]() { addSitesRoutes(m_vpnProtocol->vpnGateway(), m_settings->routeMode()); });
|
||||
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
|
||||
iface->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0/1");
|
||||
iface->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "128.0.0.0/1");
|
||||
if (!ContainerProps::isAwgContainer(container) &&
|
||||
container != DockerContainer::WireGuard) {
|
||||
QString dns1 = m_vpnConfiguration.value(config_key::dns1).toString();
|
||||
QString dns2 = m_vpnConfiguration.value(config_key::dns2).toString();
|
||||
|
||||
iface->routeAddList(m_vpnProtocol->routeGateway(), QStringList() << remoteAddress());
|
||||
addSitesRoutes(m_vpnProtocol->routeGateway(), m_settings->routeMode());
|
||||
// TODO: add error code handling for all routeAddList (or rework the code below)
|
||||
iface->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << dns1 << dns2);
|
||||
|
||||
if (m_settings->isSitesSplitTunnelingEnabled()) {
|
||||
iface->routeDeleteList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0");
|
||||
// qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << forwardIps.size();
|
||||
if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
|
||||
QTimer::singleShot(1000, m_vpnProtocol.data(),
|
||||
[this]() { addSitesRoutes(m_vpnProtocol->vpnGateway(), m_settings->routeMode()); });
|
||||
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
|
||||
iface->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0/1");
|
||||
iface->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "128.0.0.0/1");
|
||||
|
||||
iface->routeAddList(m_vpnProtocol->routeGateway(), QStringList() << remoteAddress());
|
||||
addSitesRoutes(m_vpnProtocol->routeGateway(), m_settings->routeMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case Vpn::ConnectionState::Disconnected:
|
||||
case Vpn::ConnectionState::Error: {
|
||||
auto flushDns = iface->flushDns();
|
||||
if (flushDns.waitForFinished() && flushDns.returnValue())
|
||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully flushed DNS";
|
||||
else
|
||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to flush DNS";
|
||||
|
||||
if (container != DockerContainer::Ipsec) {
|
||||
if (startNetworkCheckIfReady()) {
|
||||
m_pendingNetworkCheck = false;
|
||||
} else {
|
||||
m_pendingNetworkCheck = true;
|
||||
qWarning() << "Deferring startNetworkCheck; missing gateway/local address"
|
||||
<< m_vpnProtocol->vpnGateway() << m_vpnProtocol->vpnLocalAddress();
|
||||
}
|
||||
} else {
|
||||
m_pendingNetworkCheck = false;
|
||||
}
|
||||
|
||||
} else if (state == Vpn::ConnectionState::Error) {
|
||||
m_pendingNetworkCheck = false;
|
||||
iface->flushDns();
|
||||
|
||||
if (m_settings->isSitesSplitTunnelingEnabled()) {
|
||||
if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
|
||||
iface->clearSavedRoutes();
|
||||
}
|
||||
}
|
||||
} else if (state == Vpn::ConnectionState::Connecting) {
|
||||
|
||||
} else if (state == Vpn::ConnectionState::Disconnected) {
|
||||
m_pendingNetworkCheck = false;
|
||||
auto result = iface->stopNetworkCheck();
|
||||
result.waitForFinished(3000);
|
||||
auto clearSavedRoutes = iface->clearSavedRoutes();
|
||||
if (clearSavedRoutes.waitForFinished() && clearSavedRoutes.returnValue())
|
||||
qDebug() << "VpnConnection::onConnectionStateChanged: Successfully cleared saved routes";
|
||||
else
|
||||
qWarning() << "VpnConnection::onConnectionStateChanged: Failed to clear saved routes";
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
#endif
|
||||
@@ -140,7 +136,6 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
m_checkTimer.stop();
|
||||
}
|
||||
#endif
|
||||
emit connectionStateChanged(state);
|
||||
}
|
||||
|
||||
const QString &VpnConnection::remoteAddress() const
|
||||
@@ -185,7 +180,11 @@ void VpnConnection::addSitesRoutes(const QString &gw, Settings::RouteMode mode)
|
||||
});
|
||||
m_settings->addVpnSite(mode, site, ip);
|
||||
}
|
||||
flushDns();
|
||||
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
auto reply = iface->flushDns();
|
||||
if (reply.waitForFinished() || !reply.returnValue())
|
||||
qWarning() << "VpnConnection::addSitesRoutes: Failed to flush DNS";
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -200,48 +199,6 @@ QSharedPointer<VpnProtocol> VpnConnection::vpnProtocol() const
|
||||
return m_vpnProtocol;
|
||||
}
|
||||
|
||||
void VpnConnection::addRoutes(const QStringList &ips)
|
||||
{
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
if (connectionState() == Vpn::ConnectionState::Connected) {
|
||||
if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
|
||||
iface->routeAddList(m_vpnProtocol->vpnGateway(), ips);
|
||||
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
|
||||
iface->routeAddList(m_vpnProtocol->routeGateway(), ips);
|
||||
}
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void VpnConnection::deleteRoutes(const QStringList &ips)
|
||||
{
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
if (connectionState() == Vpn::ConnectionState::Connected) {
|
||||
if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
|
||||
iface->routeDeleteList(vpnProtocol()->vpnGateway(), ips);
|
||||
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
|
||||
iface->routeDeleteList(m_vpnProtocol->routeGateway(), ips);
|
||||
}
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void VpnConnection::flushDns()
|
||||
{
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
auto reply = iface->flushDns();
|
||||
if (reply.waitForFinished(1000) || !reply.returnValue()) {
|
||||
qWarning() << "VpnConnection::flushDns(): Failed to flush DNS";
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void VpnConnection::disconnectSlots()
|
||||
{
|
||||
if (m_vpnProtocol) {
|
||||
@@ -265,19 +222,15 @@ ErrorCode VpnConnection::lastError() const
|
||||
void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &vpnConfiguration)
|
||||
{
|
||||
qDebug() << QString("ConnectToVpn, Server index is %1, container is %2, route mode is")
|
||||
qDebug() << QString("Trying to connect to VPN, server index is %1, container is %2, route mode is")
|
||||
.arg(serverIndex)
|
||||
.arg(ContainerProps::containerToString(container))
|
||||
<< m_settings->routeMode();
|
||||
|
||||
m_remoteAddress = NetworkUtilities::getIPAddress(credentials.hostName);
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Connecting);
|
||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||
|
||||
m_pendingNetworkCheck = false;
|
||||
m_vpnConfiguration = vpnConfiguration;
|
||||
m_serverIndex = serverIndex;
|
||||
m_serverCredentials = credentials;
|
||||
m_dockerContainer = container;
|
||||
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
if (m_vpnProtocol) {
|
||||
@@ -293,7 +246,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
m_vpnProtocol.reset(VpnProtocol::factory(container, m_vpnConfiguration));
|
||||
if (!m_vpnProtocol) {
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Error);
|
||||
setConnectionState(Vpn::ConnectionState::Error);
|
||||
return;
|
||||
}
|
||||
m_vpnProtocol->prepare();
|
||||
@@ -311,75 +264,23 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
|
||||
|
||||
createProtocolConnections();
|
||||
|
||||
ErrorCode errorCode = m_vpnProtocol->start();
|
||||
if (errorCode != ErrorCode::NoError)
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Error);
|
||||
}
|
||||
|
||||
void VpnConnection::restartConnection()
|
||||
{
|
||||
// Only reconnect if VPN was connected before sleep/network change
|
||||
if (!m_wasConnectedBeforeSleep) {
|
||||
qDebug() << "VPN was not connected before sleep/network change, skipping reconnection";
|
||||
return;
|
||||
if (ErrorCode err = m_vpnProtocol->start(); err != ErrorCode::NoError) {
|
||||
setConnectionState(Vpn::ConnectionState::Error);
|
||||
emit vpnProtocolError(err);
|
||||
}
|
||||
|
||||
qDebug() << "VPN was connected before sleep/network change, attempting reconnection";
|
||||
this->disconnectFromVpn();
|
||||
#ifdef Q_OS_LINUX
|
||||
QThread::msleep(5000);
|
||||
#endif
|
||||
this->connectToVpn(m_serverIndex, m_serverCredentials, m_dockerContainer, m_vpnConfiguration);
|
||||
|
||||
// Reset the flag after reconnection attempt
|
||||
m_wasConnectedBeforeSleep = false;
|
||||
}
|
||||
|
||||
void VpnConnection::createProtocolConnections()
|
||||
{
|
||||
connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
|
||||
connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(Vpn::ConnectionState)), this,
|
||||
SLOT(onConnectionStateChanged(Vpn::ConnectionState)));
|
||||
connect(m_vpnProtocol.data(), &VpnProtocol::connectionStateChanged, this, &VpnConnection::setConnectionState);
|
||||
connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64)));
|
||||
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
if (m_connectionLoseHandle)
|
||||
disconnect(m_connectionLoseHandle);
|
||||
if (m_networkChangeHandle)
|
||||
disconnect(m_networkChangeHandle);
|
||||
m_connectionLoseHandle = QMetaObject::Connection();
|
||||
m_networkChangeHandle = QMetaObject::Connection();
|
||||
|
||||
// TODO: replace unsafe IpcClient::Interface() calls
|
||||
m_connectionLoseHandle = connect(IpcClient::Interface().data(), &IpcInterfaceReplica::connectionLose,
|
||||
this, [this]() {
|
||||
qDebug() << "Connection Lose";
|
||||
auto result = IpcClient::Interface()->stopNetworkCheck();
|
||||
result.waitForFinished(3000);
|
||||
// Track VPN state before connection loss
|
||||
m_wasConnectedBeforeSleep = isConnected();
|
||||
qDebug() << "VPN was connected before connection loss:" << m_wasConnectedBeforeSleep;
|
||||
this->restartConnection();
|
||||
});
|
||||
m_networkChangeHandle = connect(IpcClient::Interface().data(), &IpcInterfaceReplica::networkChange,
|
||||
this, [this]() {
|
||||
qDebug() << "Network change";
|
||||
// Track VPN state before network change (including sleep/wake)
|
||||
m_wasConnectedBeforeSleep = isConnected();
|
||||
qDebug() << "VPN was connected before network change:" << m_wasConnectedBeforeSleep;
|
||||
this->restartConnection();
|
||||
});
|
||||
connect(m_vpnProtocol.data(), &VpnProtocol::tunnelAddressesUpdated,
|
||||
this, [this](const QString& gateway, const QString& localAddress) {
|
||||
Q_UNUSED(gateway)
|
||||
Q_UNUSED(localAddress)
|
||||
if (connectionState() != Vpn::ConnectionState::Connected) {
|
||||
return;
|
||||
}
|
||||
if (startNetworkCheckIfReady()) {
|
||||
m_pendingNetworkCheck = false;
|
||||
}
|
||||
});
|
||||
IpcClient::withInterface([this](QSharedPointer<IpcInterfaceReplica> rep) {
|
||||
connect(rep.data(), &IpcInterfaceReplica::networkChanged, this, &VpnConnection::reconnectToVpn, Qt::QueuedConnection);
|
||||
connect(rep.data(), &IpcInterfaceReplica::wakeup, this, &VpnConnection::reconnectToVpn, Qt::QueuedConnection);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -482,28 +383,13 @@ void VpnConnection::appendSplitTunnelingConfig()
|
||||
|
||||
m_vpnConfiguration.insert(config_key::appSplitTunnelType, appsRouteMode);
|
||||
m_vpnConfiguration.insert(config_key::splitTunnelApps, appsJsonArray);
|
||||
}
|
||||
|
||||
bool VpnConnection::startNetworkCheckIfReady()
|
||||
{
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
if (!m_vpnProtocol || m_dockerContainer == DockerContainer::Ipsec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString gateway = m_vpnProtocol->vpnGateway();
|
||||
const QString localAddress = m_vpnProtocol->vpnLocalAddress();
|
||||
if (gateway.isEmpty() || localAddress.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
QRemoteObjectPendingReply<bool> reply = iface->startNetworkCheck(gateway, localAddress);
|
||||
return reply.waitForFinished(1000) && reply.returnValue();
|
||||
});
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
qDebug() << QString("Site split tunneling is %1, route mode is %2")
|
||||
.arg(m_settings->isSitesSplitTunnelingEnabled() ? "enabled" : "disabled")
|
||||
.arg(routeMode);
|
||||
qDebug() << QString("App split tunneling is %1, route mode is %2")
|
||||
.arg(m_settings->isAppsSplitTunnelingEnabled() ? "enabled" : "disabled")
|
||||
.arg(appsRouteMode);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
@@ -537,6 +423,27 @@ QString VpnConnection::bytesPerSecToText(quint64 bytes)
|
||||
return QString("%1 %2").arg(QString::number(mbps, 'f', 2)).arg(tr("Mbps")); // Mbit/s
|
||||
}
|
||||
|
||||
void VpnConnection::reconnectToVpn() {
|
||||
if (m_vpnProtocol.isNull())
|
||||
return;
|
||||
|
||||
if (m_connectionState != Vpn::ConnectionState::Connected) {
|
||||
qWarning() << QString("Reconnect triggered on %1 during inappropriate state: %2; ignoring slot")
|
||||
.arg(QMetaEnum::fromType<Vpn::ConnectionState>().valueToKey(m_connectionState));
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Reconnect triggered. Reconnecting to the server";
|
||||
|
||||
setConnectionState(Vpn::ConnectionState::Reconnecting);
|
||||
|
||||
m_vpnProtocol->stop();
|
||||
if (ErrorCode err = m_vpnProtocol->start(); err != ErrorCode::NoError) {
|
||||
setConnectionState(Vpn::ConnectionState::Error);
|
||||
emit vpnProtocolError(err);
|
||||
}
|
||||
}
|
||||
|
||||
void VpnConnection::disconnectFromVpn()
|
||||
{
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
@@ -546,27 +453,11 @@ void VpnConnection::disconnectFromVpn()
|
||||
#endif
|
||||
|
||||
if (m_vpnProtocol.isNull()) {
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Disconnected);
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
return;
|
||||
}
|
||||
|
||||
m_vpnProtocol->stop();
|
||||
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
QRemoteObjectPendingReply<bool> flushReply = iface->flushDns();
|
||||
if (flushReply.waitForFinished(5000) && flushReply.returnValue())
|
||||
qDebug() << "VpnConnection::disconnectFromVpn(): Successfully flushed DNS";
|
||||
else
|
||||
qWarning() << "VpnConnection::disconnectFromVpn(): Failed to flush DNS";
|
||||
|
||||
QRemoteObjectPendingReply<bool> clearSavedRoutesReply = iface->clearSavedRoutes();
|
||||
if (clearSavedRoutesReply.waitForFinished(5000) && clearSavedRoutesReply.returnValue())
|
||||
qDebug() << "VpnConnection::disconnectFromVpn(): Successfully cleared saved routes";
|
||||
else
|
||||
qWarning() << "VpnConnection::disconnectFromVpn(): Failed to clear saved routes";
|
||||
});
|
||||
#endif
|
||||
setConnectionState(Vpn::ConnectionState::Disconnecting);
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
auto *const connection = new QMetaObject::Connection;
|
||||
@@ -578,9 +469,10 @@ void VpnConnection::disconnectFromVpn()
|
||||
delete connection;
|
||||
}
|
||||
});
|
||||
m_vpnProtocol->stop();
|
||||
#endif
|
||||
|
||||
m_vpnProtocol->stop();
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(AMNEZIA_DESKTOP)
|
||||
m_vpnProtocol->deleteLater();
|
||||
#endif
|
||||
@@ -588,27 +480,12 @@ void VpnConnection::disconnectFromVpn()
|
||||
m_vpnProtocol = nullptr;
|
||||
}
|
||||
|
||||
Vpn::ConnectionState VpnConnection::connectionState()
|
||||
{
|
||||
if (!m_vpnProtocol)
|
||||
return Vpn::ConnectionState::Disconnected;
|
||||
return m_vpnProtocol->connectionState();
|
||||
}
|
||||
|
||||
bool VpnConnection::isConnected() const
|
||||
{
|
||||
if (m_vpnProtocol.isNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_vpnProtocol->isConnected();
|
||||
}
|
||||
|
||||
bool VpnConnection::isDisconnected() const
|
||||
{
|
||||
if (m_vpnProtocol.isNull()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_vpnProtocol->isDisconnected();
|
||||
void VpnConnection::setConnectionState(Vpn::ConnectionState state) {
|
||||
onConnectionStateChanged(state);
|
||||
|
||||
if (state == Vpn::Disconnected && m_connectionState == Vpn::Reconnecting)
|
||||
return;
|
||||
|
||||
m_connectionState = state;
|
||||
emit connectionStateChanged(state);
|
||||
}
|
||||
|
||||
@@ -34,10 +34,6 @@ public:
|
||||
|
||||
ErrorCode lastError() const;
|
||||
|
||||
bool isConnected() const;
|
||||
bool isDisconnected() const;
|
||||
|
||||
Vpn::ConnectionState connectionState();
|
||||
QSharedPointer<VpnProtocol> vpnProtocol() const;
|
||||
|
||||
const QString &remoteAddress() const;
|
||||
@@ -48,15 +44,10 @@ public:
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
void connectToVpn(int serverIndex,
|
||||
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &vpnConfiguration);
|
||||
|
||||
void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &vpnConfiguration);
|
||||
void reconnectToVpn();
|
||||
void disconnectFromVpn();
|
||||
void restartConnection();
|
||||
|
||||
void addRoutes(const QStringList &ips);
|
||||
void deleteRoutes(const QStringList &ips);
|
||||
void flushDns();
|
||||
void onKillSwitchModeChanged(bool enabled);
|
||||
void disconnectSlots();
|
||||
|
||||
@@ -71,10 +62,10 @@ protected slots:
|
||||
void onBytesChanged(quint64 receivedBytes, quint64 sentBytes);
|
||||
void onConnectionStateChanged(Vpn::ConnectionState state);
|
||||
|
||||
void setConnectionState(Vpn::ConnectionState state);
|
||||
|
||||
protected:
|
||||
QSharedPointer<VpnProtocol> m_vpnProtocol;
|
||||
QMetaObject::Connection m_connectionLoseHandle;
|
||||
QMetaObject::Connection m_networkChangeHandle;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
@@ -82,14 +73,6 @@ private:
|
||||
QJsonObject m_routeMode;
|
||||
QString m_remoteAddress;
|
||||
|
||||
ServerCredentials m_serverCredentials;
|
||||
int m_serverIndex;
|
||||
DockerContainer m_dockerContainer;
|
||||
|
||||
// Track VPN state before sleep for smart reconnection
|
||||
bool m_wasConnectedBeforeSleep = false;
|
||||
bool m_pendingNetworkCheck = false;
|
||||
|
||||
// Only for iOS for now, check counters
|
||||
QTimer m_checkTimer;
|
||||
|
||||
@@ -100,11 +83,12 @@ private:
|
||||
void createAndroidConnections();
|
||||
#endif
|
||||
|
||||
Vpn::ConnectionState m_connectionState;
|
||||
|
||||
void createProtocolConnections();
|
||||
|
||||
void appendSplitTunnelingConfig();
|
||||
void appendKillSwitchConfig();
|
||||
bool startNetworkCheckIfReady();
|
||||
};
|
||||
|
||||
#endif // VPNCONNECTION_H
|
||||
|
||||
9
cmake/conan_bootstrap.cmake
Normal file
9
cmake/conan_bootstrap.cmake
Normal file
@@ -0,0 +1,9 @@
|
||||
find_program(CONAN_COMMAND "conan" REQUIRED HINTS /opt/homebrew/bin)
|
||||
|
||||
file(GLOB_RECURSE LOCAL_RECIPES "${CMAKE_SOURCE_DIR}/recipes/*/conanfile.py")
|
||||
foreach(RECIPE ${LOCAL_RECIPES})
|
||||
get_filename_component(RECIPE_DIR ${RECIPE} DIRECTORY)
|
||||
execute_process(
|
||||
COMMAND ${CONAN_COMMAND} export ${RECIPE_DIR}
|
||||
)
|
||||
endforeach()
|
||||
722
cmake/conan_provider.cmake
Normal file
722
cmake/conan_provider.cmake
Normal file
@@ -0,0 +1,722 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2024 JFrog
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
set(CONAN_MINIMUM_VERSION 2.0.5)
|
||||
|
||||
# Create a new policy scope and set the minimum required cmake version so the
|
||||
# features behind a policy setting like if(... IN_LIST ...) behaves as expected
|
||||
# even if the parent project does not specify a minimum cmake version or a minimum
|
||||
# version less than this module requires (e.g. 3.0) before the first project() call.
|
||||
# (see: https://cmake.org/cmake/help/latest/variable/CMAKE_PROJECT_TOP_LEVEL_INCLUDES.html)
|
||||
#
|
||||
# The policy-affecting calls like cmake_policy(SET...) or `cmake_minimum_required` only
|
||||
# affects the current policy scope, i.e. between the PUSH and POP in this case.
|
||||
#
|
||||
# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Policies.html#the-policy-stack
|
||||
cmake_policy(PUSH)
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
|
||||
function(detect_os os os_api_level os_sdk os_subsystem os_version)
|
||||
# it could be cross compilation
|
||||
message(STATUS "CMake-Conan: cmake_system_name=${CMAKE_SYSTEM_NAME}")
|
||||
if(CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL "Generic")
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
set(${os} Macos PARENT_SCOPE)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "QNX")
|
||||
set(${os} Neutrino PARENT_SCOPE)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "CYGWIN")
|
||||
set(${os} Windows PARENT_SCOPE)
|
||||
set(${os_subsystem} cygwin PARENT_SCOPE)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "^MSYS")
|
||||
set(${os} Windows PARENT_SCOPE)
|
||||
set(${os_subsystem} msys2 PARENT_SCOPE)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
||||
# https://github.com/emscripten-core/emscripten/blob/4.0.6/cmake/Modules/Platform/Emscripten.cmake#L17C1-L17C34
|
||||
set(${os} Emscripten PARENT_SCOPE)
|
||||
else()
|
||||
set(${os} ${CMAKE_SYSTEM_NAME} PARENT_SCOPE)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
if(DEFINED ANDROID_PLATFORM)
|
||||
string(REGEX MATCH "[0-9]+" _os_api_level ${ANDROID_PLATFORM})
|
||||
elseif(DEFINED CMAKE_SYSTEM_VERSION)
|
||||
set(_os_api_level ${CMAKE_SYSTEM_VERSION})
|
||||
endif()
|
||||
message(STATUS "CMake-Conan: android api level=${_os_api_level}")
|
||||
set(${os_api_level} ${_os_api_level} PARENT_SCOPE)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|watchOS")
|
||||
# CMAKE_OSX_SYSROOT contains the full path to the SDK for MakeFile/Ninja
|
||||
# generators, but just has the original input string for Xcode.
|
||||
if(NOT IS_DIRECTORY ${CMAKE_OSX_SYSROOT})
|
||||
set(_os_sdk ${CMAKE_OSX_SYSROOT})
|
||||
else()
|
||||
if(CMAKE_OSX_SYSROOT MATCHES Simulator)
|
||||
set(apple_platform_suffix simulator)
|
||||
else()
|
||||
set(apple_platform_suffix os)
|
||||
endif()
|
||||
if(CMAKE_OSX_SYSROOT MATCHES AppleTV)
|
||||
set(_os_sdk "appletv${apple_platform_suffix}")
|
||||
elseif(CMAKE_OSX_SYSROOT MATCHES iPhone)
|
||||
set(_os_sdk "iphone${apple_platform_suffix}")
|
||||
elseif(CMAKE_OSX_SYSROOT MATCHES Watch)
|
||||
set(_os_sdk "watch${apple_platform_suffix}")
|
||||
endif()
|
||||
endif()
|
||||
if(DEFINED os_sdk)
|
||||
message(STATUS "CMake-Conan: cmake_osx_sysroot=${CMAKE_OSX_SYSROOT}")
|
||||
set(${os_sdk} ${_os_sdk} PARENT_SCOPE)
|
||||
endif()
|
||||
if(DEFINED CMAKE_OSX_DEPLOYMENT_TARGET)
|
||||
message(STATUS "CMake-Conan: cmake_osx_deployment_target=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
set(${os_version} ${CMAKE_OSX_DEPLOYMENT_TARGET} PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(detect_arch arch)
|
||||
# CMAKE_OSX_ARCHITECTURES can contain multiple architectures, but Conan only supports one.
|
||||
# Therefore this code only finds one. If the recipes support multiple architectures, the
|
||||
# build will work. Otherwise, there will be a linker error for the missing architecture(s).
|
||||
if(DEFINED CMAKE_OSX_ARCHITECTURES)
|
||||
string(REPLACE " " ";" apple_arch_list "${CMAKE_OSX_ARCHITECTURES}")
|
||||
list(LENGTH apple_arch_list apple_arch_count)
|
||||
if(apple_arch_count GREATER 1)
|
||||
message(WARNING "CMake-Conan: Multiple architectures detected, this will only work if Conan recipe(s) produce fat binaries.")
|
||||
endif()
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|watchOS" AND NOT CMAKE_OSX_ARCHITECTURES STREQUAL "")
|
||||
set(host_arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
elseif(MSVC)
|
||||
set(host_arch ${CMAKE_CXX_COMPILER_ARCHITECTURE_ID})
|
||||
else()
|
||||
set(host_arch ${CMAKE_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
if(host_arch MATCHES "aarch64|arm64|ARM64")
|
||||
list(APPEND _arch armv8)
|
||||
endif()
|
||||
if(host_arch MATCHES "armv7|armv7-a|armv7l|ARMV7")
|
||||
list(APPEND _arch armv7)
|
||||
endif()
|
||||
if(host_arch MATCHES armv7s)
|
||||
list(APPEND _arch armv7s)
|
||||
endif()
|
||||
if(host_arch MATCHES "i686|i386|X86")
|
||||
list(APPEND _arch x86)
|
||||
endif()
|
||||
if(host_arch MATCHES "AMD64|amd64|x86_64|x64")
|
||||
list(APPEND _arch x86_64)
|
||||
endif()
|
||||
if(EMSCRIPTEN)
|
||||
# https://github.com/emscripten-core/emscripten/blob/4.0.6/cmake/Modules/Platform/Emscripten.cmake#L294C1-L294C80
|
||||
list(APPEND _arch wasm)
|
||||
endif()
|
||||
message(STATUS "CMake-Conan: cmake_system_processor=${_arch}")
|
||||
list(JOIN _arch "|" _arch)
|
||||
set(${arch} ${_arch} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(detect_cxx_standard compiler cxx_standard)
|
||||
set(${cxx_standard} ${CMAKE_CXX_STANDARD} PARENT_SCOPE)
|
||||
if(CMAKE_CXX_EXTENSIONS)
|
||||
if(compiler STREQUAL "msvc")
|
||||
set(${cxx_standard} "${CMAKE_CXX_STANDARD}" PARENT_SCOPE)
|
||||
else()
|
||||
set(${cxx_standard} "gnu${CMAKE_CXX_STANDARD}" PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
macro(detect_gnu_libstdcxx)
|
||||
# _conan_is_gnu_libstdcxx true if GNU libstdc++
|
||||
check_cxx_source_compiles("
|
||||
#include <cstddef>
|
||||
#if !defined(__GLIBCXX__) && !defined(__GLIBCPP__)
|
||||
static_assert(false);
|
||||
#endif
|
||||
int main(){}" _conan_is_gnu_libstdcxx)
|
||||
|
||||
# _conan_gnu_libstdcxx_is_cxx11_abi true if C++11 ABI
|
||||
check_cxx_source_compiles("
|
||||
#include <string>
|
||||
static_assert(sizeof(std::string) != sizeof(void*), \"using libstdc++\");
|
||||
int main () {}" _conan_gnu_libstdcxx_is_cxx11_abi)
|
||||
|
||||
set(_conan_gnu_libstdcxx_suffix "")
|
||||
if(_conan_gnu_libstdcxx_is_cxx11_abi)
|
||||
set(_conan_gnu_libstdcxx_suffix "11")
|
||||
endif()
|
||||
unset (_conan_gnu_libstdcxx_is_cxx11_abi)
|
||||
endmacro()
|
||||
|
||||
|
||||
macro(detect_libcxx)
|
||||
# _conan_is_libcxx true if LLVM libc++
|
||||
check_cxx_source_compiles("
|
||||
#include <cstddef>
|
||||
#if !defined(_LIBCPP_VERSION)
|
||||
static_assert(false);
|
||||
#endif
|
||||
int main(){}" _conan_is_libcxx)
|
||||
endmacro()
|
||||
|
||||
|
||||
function(detect_lib_cxx lib_cxx)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
message(STATUS "CMake-Conan: android_stl=${CMAKE_ANDROID_STL_TYPE}")
|
||||
set(${lib_cxx} ${CMAKE_ANDROID_STL_TYPE} PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
detect_gnu_libstdcxx()
|
||||
set(${lib_cxx} "libstdc++${_conan_gnu_libstdcxx_suffix}" PARENT_SCOPE)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang")
|
||||
set(${lib_cxx} "libc++" PARENT_SCOPE)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
# Check for libc++
|
||||
detect_libcxx()
|
||||
if(_conan_is_libcxx)
|
||||
set(${lib_cxx} "libc++" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Check for libstdc++
|
||||
detect_gnu_libstdcxx()
|
||||
if(_conan_is_gnu_libstdcxx)
|
||||
set(${lib_cxx} "libstdc++${_conan_gnu_libstdcxx_suffix}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# TODO: it would be an error if we reach this point
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
# Do nothing - compiler.runtime and compiler.runtime_type
|
||||
# should be handled separately: https://github.com/conan-io/cmake-conan/pull/516
|
||||
return()
|
||||
else()
|
||||
# TODO: unable to determine, ask user to provide a full profile file instead
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(detect_compiler compiler compiler_version compiler_runtime compiler_runtime_type)
|
||||
if(DEFINED CMAKE_CXX_COMPILER_ID)
|
||||
set(_compiler ${CMAKE_CXX_COMPILER_ID})
|
||||
set(_compiler_version ${CMAKE_CXX_COMPILER_VERSION})
|
||||
else()
|
||||
if(NOT DEFINED CMAKE_C_COMPILER_ID)
|
||||
message(FATAL_ERROR "C or C++ compiler not defined")
|
||||
endif()
|
||||
set(_compiler ${CMAKE_C_COMPILER_ID})
|
||||
set(_compiler_version ${CMAKE_C_COMPILER_VERSION})
|
||||
endif()
|
||||
|
||||
message(STATUS "CMake-Conan: CMake compiler=${_compiler}")
|
||||
message(STATUS "CMake-Conan: CMake compiler version=${_compiler_version}")
|
||||
|
||||
if(_compiler MATCHES MSVC)
|
||||
set(_compiler "msvc")
|
||||
string(SUBSTRING ${MSVC_VERSION} 0 3 _compiler_version)
|
||||
# Configure compiler.runtime and compiler.runtime_type settings for MSVC
|
||||
if(CMAKE_MSVC_RUNTIME_LIBRARY)
|
||||
set(_msvc_runtime_library ${CMAKE_MSVC_RUNTIME_LIBRARY})
|
||||
else()
|
||||
set(_msvc_runtime_library MultiThreaded$<$<CONFIG:Debug>:Debug>DLL) # default value documented by CMake
|
||||
endif()
|
||||
|
||||
set(_KNOWN_MSVC_RUNTIME_VALUES "")
|
||||
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded MultiThreadedDLL)
|
||||
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreadedDebug MultiThreadedDebugDLL)
|
||||
list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded$<$<CONFIG:Debug>:Debug> MultiThreaded$<$<CONFIG:Debug>:Debug>DLL)
|
||||
|
||||
# only accept the 6 possible values, otherwise we don't don't know to map this
|
||||
if(NOT _msvc_runtime_library IN_LIST _KNOWN_MSVC_RUNTIME_VALUES)
|
||||
message(FATAL_ERROR "CMake-Conan: unable to map MSVC runtime: ${_msvc_runtime_library} to Conan settings")
|
||||
endif()
|
||||
|
||||
# Runtime is "dynamic" in all cases if it ends in DLL
|
||||
if(_msvc_runtime_library MATCHES ".*DLL$")
|
||||
set(_compiler_runtime "dynamic")
|
||||
else()
|
||||
set(_compiler_runtime "static")
|
||||
endif()
|
||||
message(STATUS "CMake-Conan: CMake compiler.runtime=${_compiler_runtime}")
|
||||
|
||||
# Only define compiler.runtime_type when explicitly requested
|
||||
# If a generator expression is used, let Conan handle it conditional on build_type
|
||||
if(NOT _msvc_runtime_library MATCHES "<CONFIG:Debug>:Debug>")
|
||||
if(_msvc_runtime_library MATCHES "Debug")
|
||||
set(_compiler_runtime_type "Debug")
|
||||
else()
|
||||
set(_compiler_runtime_type "Release")
|
||||
endif()
|
||||
message(STATUS "CMake-Conan: CMake compiler.runtime_type=${_compiler_runtime_type}")
|
||||
endif()
|
||||
|
||||
unset(_KNOWN_MSVC_RUNTIME_VALUES)
|
||||
|
||||
elseif(_compiler MATCHES AppleClang)
|
||||
set(_compiler "apple-clang")
|
||||
string(REPLACE "." ";" VERSION_LIST ${_compiler_version})
|
||||
list(GET VERSION_LIST 0 _compiler_version)
|
||||
elseif(_compiler MATCHES Clang)
|
||||
set(_compiler "clang")
|
||||
string(REPLACE "." ";" VERSION_LIST ${_compiler_version})
|
||||
list(GET VERSION_LIST 0 _compiler_version)
|
||||
elseif(_compiler MATCHES GNU)
|
||||
set(_compiler "gcc")
|
||||
string(REPLACE "." ";" VERSION_LIST ${_compiler_version})
|
||||
list(GET VERSION_LIST 0 _compiler_version)
|
||||
endif()
|
||||
|
||||
message(STATUS "CMake-Conan: [settings] compiler=${_compiler}")
|
||||
message(STATUS "CMake-Conan: [settings] compiler.version=${_compiler_version}")
|
||||
if (_compiler_runtime)
|
||||
message(STATUS "CMake-Conan: [settings] compiler.runtime=${_compiler_runtime}")
|
||||
endif()
|
||||
if (_compiler_runtime_type)
|
||||
message(STATUS "CMake-Conan: [settings] compiler.runtime_type=${_compiler_runtime_type}")
|
||||
endif()
|
||||
|
||||
set(${compiler} ${_compiler} PARENT_SCOPE)
|
||||
set(${compiler_version} ${_compiler_version} PARENT_SCOPE)
|
||||
set(${compiler_runtime} ${_compiler_runtime} PARENT_SCOPE)
|
||||
set(${compiler_runtime_type} ${_compiler_runtime_type} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(detect_build_type build_type)
|
||||
get_property(multiconfig_generator GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(NOT multiconfig_generator)
|
||||
# Only set when we know we are in a single-configuration generator
|
||||
# Note: we may want to fail early if `CMAKE_BUILD_TYPE` is not defined
|
||||
set(${build_type} ${CMAKE_BUILD_TYPE} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
macro(set_conan_compiler_if_appleclang lang command output_variable)
|
||||
if(CMAKE_${lang}_COMPILER_ID STREQUAL "AppleClang")
|
||||
execute_process(COMMAND xcrun --find ${command}
|
||||
OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
cmake_path(GET _xcrun_out PARENT_PATH _xcrun_toolchain_path)
|
||||
cmake_path(GET CMAKE_${lang}_COMPILER PARENT_PATH _compiler_parent_path)
|
||||
if ("${_xcrun_toolchain_path}" STREQUAL "${_compiler_parent_path}")
|
||||
set(${output_variable} "")
|
||||
endif()
|
||||
unset(_xcrun_out)
|
||||
unset(_xcrun_toolchain_path)
|
||||
unset(_compiler_parent_path)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
macro(append_compiler_executables_configuration)
|
||||
set(_conan_c_compiler "")
|
||||
set(_conan_cpp_compiler "")
|
||||
set(_conan_rc_compiler "")
|
||||
set(_conan_compilers_list "")
|
||||
if(CMAKE_C_COMPILER)
|
||||
set(_conan_c_compiler "\"c\":\"${CMAKE_C_COMPILER}\"")
|
||||
set_conan_compiler_if_appleclang(C cc _conan_c_compiler)
|
||||
list(APPEND _conan_compilers_list ${_conan_c_compiler})
|
||||
else()
|
||||
message(WARNING "CMake-Conan: The C compiler is not defined. "
|
||||
"Please define CMAKE_C_COMPILER or enable the C language.")
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER)
|
||||
set(_conan_cpp_compiler "\"cpp\":\"${CMAKE_CXX_COMPILER}\"")
|
||||
set_conan_compiler_if_appleclang(CXX c++ _conan_cpp_compiler)
|
||||
list(APPEND _conan_compilers_list ${_conan_cpp_compiler})
|
||||
else()
|
||||
message(WARNING "CMake-Conan: The C++ compiler is not defined. "
|
||||
"Please define CMAKE_CXX_COMPILER or enable the C++ language.")
|
||||
endif()
|
||||
if(CMAKE_RC_COMPILER)
|
||||
set(_conan_rc_compiler "\"rc\":\"${CMAKE_RC_COMPILER}\"")
|
||||
list(APPEND _conan_compilers_list ${_conan_rc_compiler})
|
||||
# Not necessary to warn if RC not defined
|
||||
endif()
|
||||
if(NOT "x${_conan_compilers_list}" STREQUAL "x")
|
||||
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
string(REPLACE ";" "," _conan_compilers_list "${_conan_compilers_list}")
|
||||
string(APPEND profile "tools.build:compiler_executables={${_conan_compilers_list}}\n")
|
||||
endif()
|
||||
endif()
|
||||
unset(_conan_c_compiler)
|
||||
unset(_conan_cpp_compiler)
|
||||
unset(_conan_rc_compiler)
|
||||
unset(_conan_compilers_list)
|
||||
endmacro()
|
||||
|
||||
|
||||
function(detect_host_profile output_file)
|
||||
detect_os(os os_api_level os_sdk os_subsystem os_version)
|
||||
detect_arch(arch)
|
||||
detect_compiler(compiler compiler_version compiler_runtime compiler_runtime_type)
|
||||
detect_cxx_standard(${compiler} compiler_cppstd)
|
||||
detect_lib_cxx(compiler_libcxx)
|
||||
detect_build_type(build_type)
|
||||
|
||||
set(profile "")
|
||||
string(APPEND profile "[settings]\n")
|
||||
if(arch)
|
||||
string(APPEND profile arch=${arch} "\n")
|
||||
endif()
|
||||
if(os)
|
||||
string(APPEND profile os=${os} "\n")
|
||||
endif()
|
||||
if(os_api_level)
|
||||
string(APPEND profile os.api_level=${os_api_level} "\n")
|
||||
endif()
|
||||
if(os_version)
|
||||
string(APPEND profile os.version=${os_version} "\n")
|
||||
endif()
|
||||
if(os_sdk)
|
||||
string(APPEND profile os.sdk=${os_sdk} "\n")
|
||||
endif()
|
||||
if(os_subsystem)
|
||||
string(APPEND profile os.subsystem=${os_subsystem} "\n")
|
||||
endif()
|
||||
if(compiler)
|
||||
string(APPEND profile compiler=${compiler} "\n")
|
||||
endif()
|
||||
if(compiler_version)
|
||||
string(APPEND profile compiler.version=${compiler_version} "\n")
|
||||
endif()
|
||||
if(compiler_runtime)
|
||||
string(APPEND profile compiler.runtime=${compiler_runtime} "\n")
|
||||
endif()
|
||||
if(compiler_runtime_type)
|
||||
string(APPEND profile compiler.runtime_type=${compiler_runtime_type} "\n")
|
||||
endif()
|
||||
if(compiler_cppstd)
|
||||
string(APPEND profile compiler.cppstd=${compiler_cppstd} "\n")
|
||||
endif()
|
||||
if(compiler_libcxx)
|
||||
string(APPEND profile compiler.libcxx=${compiler_libcxx} "\n")
|
||||
endif()
|
||||
if(build_type)
|
||||
string(APPEND profile "build_type=${build_type}\n")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED output_file)
|
||||
set(file_name "${CMAKE_BINARY_DIR}/profile")
|
||||
else()
|
||||
set(file_name ${output_file})
|
||||
endif()
|
||||
|
||||
string(APPEND profile "[conf]\n")
|
||||
string(APPEND profile "tools.cmake.cmaketoolchain:generator=${CMAKE_GENERATOR}\n")
|
||||
|
||||
# propagate compilers via profile
|
||||
append_compiler_executables_configuration()
|
||||
|
||||
if(os STREQUAL "Android")
|
||||
string(APPEND profile "tools.android:ndk_path=${CMAKE_ANDROID_NDK}\n")
|
||||
endif()
|
||||
|
||||
message(STATUS "CMake-Conan: Creating profile ${file_name}")
|
||||
file(WRITE ${file_name} ${profile})
|
||||
message(STATUS "CMake-Conan: Profile: \n${profile}")
|
||||
endfunction()
|
||||
|
||||
|
||||
function(conan_profile_detect_default)
|
||||
message(STATUS "CMake-Conan: Checking if a default profile exists")
|
||||
execute_process(COMMAND ${CONAN_COMMAND} profile path default
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE conan_stdout
|
||||
ERROR_VARIABLE conan_stderr
|
||||
ECHO_ERROR_VARIABLE # show the text output regardless
|
||||
ECHO_OUTPUT_VARIABLE
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
if(NOT ${return_code} EQUAL "0")
|
||||
message(STATUS "CMake-Conan: The default profile doesn't exist, detecting it.")
|
||||
execute_process(COMMAND ${CONAN_COMMAND} profile detect
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE conan_stdout
|
||||
ERROR_VARIABLE conan_stderr
|
||||
ECHO_ERROR_VARIABLE # show the text output regardless
|
||||
ECHO_OUTPUT_VARIABLE
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(conan_install)
|
||||
set(conan_output_folder ${CMAKE_BINARY_DIR}/conan)
|
||||
# Invoke "conan install" with the provided arguments
|
||||
set(conan_args -of=${conan_output_folder})
|
||||
message(STATUS "CMake-Conan: conan install ${CMAKE_SOURCE_DIR} ${conan_args} ${ARGN}")
|
||||
|
||||
|
||||
# In case there was not a valid cmake executable in the PATH, we inject the
|
||||
# same we used to invoke the provider to the PATH
|
||||
if(DEFINED PATH_TO_CMAKE_BIN)
|
||||
set(old_path $ENV{PATH})
|
||||
set(ENV{PATH} "$ENV{PATH}:${PATH_TO_CMAKE_BIN}")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${CONAN_COMMAND} install ${CMAKE_SOURCE_DIR} ${conan_args} ${ARGN} --format=json
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE conan_stdout
|
||||
ERROR_VARIABLE conan_stderr
|
||||
ECHO_ERROR_VARIABLE # show the text output regardless
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
if(DEFINED PATH_TO_CMAKE_BIN)
|
||||
set(ENV{PATH} "${old_path}")
|
||||
endif()
|
||||
|
||||
if(NOT "${return_code}" STREQUAL "0")
|
||||
message(FATAL_ERROR "Conan install failed='${return_code}'")
|
||||
endif()
|
||||
|
||||
# the files are generated in a folder that depends on the layout used, if
|
||||
# one is specified, but we don't know a priori where this is.
|
||||
# TODO: this can be made more robust if Conan can provide this in the json output
|
||||
string(JSON conan_generators_folder GET "${conan_stdout}" graph nodes 0 generators_folder)
|
||||
cmake_path(CONVERT ${conan_generators_folder} TO_CMAKE_PATH_LIST conan_generators_folder)
|
||||
|
||||
message(STATUS "CMake-Conan: CONAN_GENERATORS_FOLDER=${conan_generators_folder}")
|
||||
set_property(GLOBAL PROPERTY CONAN_GENERATORS_FOLDER "${conan_generators_folder}")
|
||||
# reconfigure on conanfile changes
|
||||
string(JSON conanfile GET "${conan_stdout}" graph nodes 0 label)
|
||||
message(STATUS "CMake-Conan: CONANFILE=${CMAKE_SOURCE_DIR}/${conanfile}")
|
||||
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/${conanfile}")
|
||||
# success
|
||||
set_property(GLOBAL PROPERTY CONAN_INSTALL_SUCCESS TRUE)
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
function(conan_get_version conan_command conan_current_version)
|
||||
execute_process(
|
||||
COMMAND ${conan_command} --version
|
||||
OUTPUT_VARIABLE conan_output
|
||||
RESULT_VARIABLE conan_result
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(conan_result)
|
||||
message(FATAL_ERROR "CMake-Conan: Error when trying to run Conan")
|
||||
endif()
|
||||
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" conan_version ${conan_output})
|
||||
set(${conan_current_version} ${conan_version} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(conan_version_check)
|
||||
set(options )
|
||||
set(one_value_args MINIMUM CURRENT)
|
||||
set(multi_value_args )
|
||||
cmake_parse_arguments(conan_version_check
|
||||
"${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
|
||||
|
||||
if(NOT conan_version_check_MINIMUM)
|
||||
message(FATAL_ERROR "CMake-Conan: Required parameter MINIMUM not set!")
|
||||
endif()
|
||||
if(NOT conan_version_check_CURRENT)
|
||||
message(FATAL_ERROR "CMake-Conan: Required parameter CURRENT not set!")
|
||||
endif()
|
||||
|
||||
if(conan_version_check_CURRENT VERSION_LESS conan_version_check_MINIMUM)
|
||||
message(FATAL_ERROR "CMake-Conan: Conan version must be ${conan_version_check_MINIMUM} or later")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
macro(construct_profile_argument argument_variable profile_list)
|
||||
set(${argument_variable} "")
|
||||
if("${profile_list}" STREQUAL "CONAN_HOST_PROFILE")
|
||||
set(_arg_flag "--profile:host=")
|
||||
elseif("${profile_list}" STREQUAL "CONAN_BUILD_PROFILE")
|
||||
set(_arg_flag "--profile:build=")
|
||||
endif()
|
||||
|
||||
set(_profile_list "${${profile_list}}")
|
||||
list(TRANSFORM _profile_list REPLACE "auto-cmake" "${CMAKE_BINARY_DIR}/conan_host_profile")
|
||||
list(TRANSFORM _profile_list PREPEND ${_arg_flag})
|
||||
set(${argument_variable} ${_profile_list})
|
||||
|
||||
unset(_arg_flag)
|
||||
unset(_profile_list)
|
||||
endmacro()
|
||||
|
||||
|
||||
macro(conan_provide_dependency method package_name)
|
||||
set_property(GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED TRUE)
|
||||
get_property(_conan_install_success GLOBAL PROPERTY CONAN_INSTALL_SUCCESS)
|
||||
if(NOT _conan_install_success)
|
||||
find_program(CONAN_COMMAND "conan" REQUIRED)
|
||||
conan_get_version(${CONAN_COMMAND} CONAN_CURRENT_VERSION)
|
||||
conan_version_check(MINIMUM ${CONAN_MINIMUM_VERSION} CURRENT ${CONAN_CURRENT_VERSION})
|
||||
message(STATUS "CMake-Conan: first find_package() found. Installing dependencies with Conan")
|
||||
if("default" IN_LIST CONAN_HOST_PROFILE OR "default" IN_LIST CONAN_BUILD_PROFILE)
|
||||
conan_profile_detect_default()
|
||||
endif()
|
||||
if("auto-cmake" IN_LIST CONAN_HOST_PROFILE)
|
||||
detect_host_profile(${CMAKE_BINARY_DIR}/conan_host_profile)
|
||||
endif()
|
||||
construct_profile_argument(_host_profile_flags CONAN_HOST_PROFILE)
|
||||
construct_profile_argument(_build_profile_flags CONAN_BUILD_PROFILE)
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/conanfile.py")
|
||||
file(READ "${CMAKE_SOURCE_DIR}/conanfile.py" outfile)
|
||||
if(NOT "${outfile}" MATCHES ".*CMakeConfigDeps.*")
|
||||
message(WARNING "Cmake-conan: CMakeConfigDeps generator was not defined in the conanfile")
|
||||
endif()
|
||||
elseif (EXISTS "${CMAKE_SOURCE_DIR}/conanfile.txt")
|
||||
file(READ "${CMAKE_SOURCE_DIR}/conanfile.txt" outfile)
|
||||
if(NOT "${outfile}" MATCHES ".*CMakeConfigDeps.*")
|
||||
message(WARNING "Cmake-conan: CMakeConfigDeps generator was not defined in the conanfile")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
get_property(_multiconfig_generator GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
|
||||
if(DEFINED CONAN_INSTALL_BUILD_CONFIGURATIONS)
|
||||
# Configurations are specified by the project or user
|
||||
set(_build_configs "${CONAN_INSTALL_BUILD_CONFIGURATIONS}")
|
||||
list(LENGTH _build_configs _build_configs_length)
|
||||
if(NOT _multiconfig_generator AND _build_configs_length GREATER 1)
|
||||
message(FATAL_ERROR "cmake-conan: when using a single-config CMake generator, "
|
||||
"please only specify a single configuration in CONAN_INSTALL_BUILD_CONFIGURATIONS")
|
||||
endif()
|
||||
unset(_build_configs_length)
|
||||
else()
|
||||
# No configuration overrides, provide sensible defaults
|
||||
if(_multiconfig_generator)
|
||||
set(_build_configs Release Debug)
|
||||
else()
|
||||
set(_build_configs ${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
list(JOIN _build_configs ", " _build_configs_msg)
|
||||
message(STATUS "CMake-Conan: Installing configuration(s): ${_build_configs_msg}")
|
||||
foreach(_build_config IN LISTS _build_configs)
|
||||
set(_self_build_config "")
|
||||
if(NOT _multiconfig_generator AND NOT _build_config STREQUAL "${CMAKE_BUILD_TYPE}")
|
||||
set(_self_build_config -s &:build_type=${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=${_build_config} ${_self_build_config} ${CONAN_INSTALL_ARGS})
|
||||
endforeach()
|
||||
|
||||
get_property(_conan_generators_folder GLOBAL PROPERTY CONAN_GENERATORS_FOLDER)
|
||||
if(EXISTS "${_conan_generators_folder}/conan_cmakedeps_paths.cmake")
|
||||
message(STATUS "CMake-Conan: Loading conan_cmakedeps_paths.cmake file")
|
||||
include(${_conan_generators_folder}/conan_cmakedeps_paths.cmake)
|
||||
endif()
|
||||
|
||||
unset(_self_build_config)
|
||||
unset(_multiconfig_generator)
|
||||
unset(_build_configs)
|
||||
unset(_build_configs_msg)
|
||||
unset(_host_profile_flags)
|
||||
unset(_build_profile_flags)
|
||||
unset(_conan_install_success)
|
||||
else()
|
||||
message(STATUS "CMake-Conan: find_package(${ARGV1}) found, 'conan install' already ran")
|
||||
unset(_conan_install_success)
|
||||
endif()
|
||||
|
||||
get_property(_conan_generators_folder GLOBAL PROPERTY CONAN_GENERATORS_FOLDER)
|
||||
|
||||
# Ensure that we consider Conan-provided packages ahead of any other,
|
||||
# irrespective of other settings that modify the search order or search paths
|
||||
# This follows the guidelines from the find_package documentation
|
||||
# (https://cmake.org/cmake/help/latest/command/find_package.html):
|
||||
# find_package (<PackageName> PATHS paths... NO_DEFAULT_PATH)
|
||||
# find_package (<PackageName>)
|
||||
|
||||
# Filter out `REQUIRED` from the argument list, as the first call may fail
|
||||
set(_find_args_${package_name} "${ARGN}")
|
||||
list(REMOVE_ITEM _find_args_${package_name} "REQUIRED")
|
||||
if(NOT "MODULE" IN_LIST _find_args_${package_name})
|
||||
find_package(${package_name} ${_find_args_${package_name}} BYPASS_PROVIDER PATHS "${_conan_generators_folder}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
|
||||
unset(_find_args_${package_name})
|
||||
endif()
|
||||
|
||||
# Invoke find_package a second time - if the first call succeeded,
|
||||
# this will simply reuse the result. If not, fall back to CMake default search
|
||||
# behaviour, also allowing modules to be searched.
|
||||
if(NOT ${package_name}_FOUND)
|
||||
list(FIND CMAKE_MODULE_PATH "${_conan_generators_folder}" _index)
|
||||
if(_index EQUAL -1)
|
||||
list(PREPEND CMAKE_MODULE_PATH "${_conan_generators_folder}")
|
||||
endif()
|
||||
unset(_index)
|
||||
find_package(${package_name} ${ARGN} BYPASS_PROVIDER)
|
||||
list(REMOVE_ITEM CMAKE_MODULE_PATH "${_conan_generators_folder}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
cmake_language(
|
||||
SET_DEPENDENCY_PROVIDER conan_provide_dependency
|
||||
SUPPORTED_METHODS FIND_PACKAGE
|
||||
)
|
||||
|
||||
|
||||
macro(conan_provide_dependency_check)
|
||||
set(_conan_provide_dependency_invoked FALSE)
|
||||
get_property(_conan_provide_dependency_invoked GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED)
|
||||
if(NOT _conan_provide_dependency_invoked)
|
||||
message(WARNING "Conan is correctly configured as dependency provider, "
|
||||
"but Conan has not been invoked. Please add at least one "
|
||||
"call to `find_package()`.")
|
||||
if(DEFINED CONAN_COMMAND)
|
||||
# supress warning in case `CONAN_COMMAND` was specified but unused.
|
||||
set(_conan_command ${CONAN_COMMAND})
|
||||
unset(_conan_command)
|
||||
endif()
|
||||
endif()
|
||||
unset(_conan_provide_dependency_invoked)
|
||||
endmacro()
|
||||
|
||||
|
||||
# Add a deferred call at the end of processing the top-level directory
|
||||
# to check if the dependency provider was invoked at all.
|
||||
cmake_language(DEFER DIRECTORY "${CMAKE_SOURCE_DIR}" CALL conan_provide_dependency_check)
|
||||
|
||||
# Configurable variables for Conan profiles
|
||||
set(CONAN_HOST_PROFILE "default;auto-cmake" CACHE STRING "Conan host profile")
|
||||
set(CONAN_BUILD_PROFILE "default" CACHE STRING "Conan build profile")
|
||||
set(CONAN_INSTALL_ARGS "--build=missing" CACHE STRING "Command line arguments for conan install")
|
||||
|
||||
find_program(_cmake_program NAMES cmake NO_PACKAGE_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH NO_CMAKE_FIND_ROOT_PATH)
|
||||
if(NOT _cmake_program)
|
||||
get_filename_component(PATH_TO_CMAKE_BIN "${CMAKE_COMMAND}" DIRECTORY)
|
||||
set(PATH_TO_CMAKE_BIN "${PATH_TO_CMAKE_BIN}" CACHE INTERNAL "Path where the CMake executable is")
|
||||
endif()
|
||||
|
||||
cmake_policy(POP)
|
||||
42
conanfile.py
Normal file
42
conanfile.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from conan import ConanFile
|
||||
|
||||
class AmneziaVPN(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
generators = "CMakeConfigDeps"
|
||||
|
||||
options = {
|
||||
"macos_ne": [True, False]
|
||||
}
|
||||
default_options = {
|
||||
"macos_ne": False
|
||||
}
|
||||
|
||||
def requirements(self):
|
||||
os = str(self.settings.os)
|
||||
|
||||
has_ne = os == "iOS" or (os == "Macos" and self.options.macos_ne)
|
||||
has_service = os == "Windows" or os == "Linux" or (os == "Macos" and not has_ne)
|
||||
|
||||
if has_service:
|
||||
if os == "Windows":
|
||||
self.requires("awg-windows/1.0.0")
|
||||
else:
|
||||
self.requires("awg-go/0.2.16")
|
||||
|
||||
self.requires("amnezia-xray-bindings/1.1.0")
|
||||
self.requires("tun2socks/2.6.0")
|
||||
self.requires("openvpn/2.7.0")
|
||||
self.requires("v2ray-rules-dat/[*]")
|
||||
|
||||
if has_ne:
|
||||
self.requires("awg-apple/2.0.1")
|
||||
self.requires("hev-socks5-tunnel/2.14.4", options={"as_framework": True})
|
||||
self.requires("openvpnadapter/1.0.0")
|
||||
|
||||
if os == "Android":
|
||||
self.requires("amnezia-libxray/1.0.0")
|
||||
self.requires("awg-android/1.1.7")
|
||||
self.requires("openvpn-pt-android/1.0.0")
|
||||
|
||||
self.requires("libssh/0.11.3@amnezia")
|
||||
self.requires("openssl/3.5.5")
|
||||
@@ -14,6 +14,8 @@ sc stop AmneziaVPN-service
|
||||
sc delete AmneziaVPN-service
|
||||
sc stop AmneziaWGTunnel$AmneziaVPN
|
||||
sc delete AmneziaWGTunnel$AmneziaVPN
|
||||
sc stop AmneziaVPNSplitTunnel
|
||||
sc delete AmneziaVPNSplitTunnel
|
||||
taskkill /IM "AmneziaVPN-service.exe" /F
|
||||
taskkill /IM "AmneziaVPN.exe" /F
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ sc stop AmneziaVPN-service
|
||||
sc delete AmneziaVPN-service
|
||||
sc stop AmneziaWGTunnel$AmneziaVPN
|
||||
sc delete AmneziaWGTunnel$AmneziaVPN
|
||||
sc stop AmneziaVPNSplitTunnel
|
||||
sc delete AmneziaVPNSplitTunnel
|
||||
taskkill /IM "AmneziaVPN-service.exe" /F
|
||||
taskkill /IM "AmneziaVPN.exe" /F
|
||||
|
||||
|
||||
66
ipc/ipc.h
66
ipc/ipc.h
@@ -11,6 +11,7 @@
|
||||
namespace amnezia {
|
||||
|
||||
enum PermittedProcess {
|
||||
Invalid,
|
||||
OpenVPN,
|
||||
Wireguard,
|
||||
Tun2Socks,
|
||||
@@ -19,16 +20,18 @@ enum PermittedProcess {
|
||||
|
||||
inline QString permittedProcessPath(PermittedProcess pid)
|
||||
{
|
||||
if (pid == PermittedProcess::OpenVPN) {
|
||||
return Utils::openVpnExecPath();
|
||||
} else if (pid == PermittedProcess::Wireguard) {
|
||||
return Utils::wireguardExecPath();
|
||||
} else if (pid == PermittedProcess::CertUtil) {
|
||||
return Utils::certUtilPath();
|
||||
} else if (pid == PermittedProcess::Tun2Socks) {
|
||||
return Utils::tun2socksPath();
|
||||
switch (pid) {
|
||||
case PermittedProcess::OpenVPN:
|
||||
return Utils::openVpnExecPath();
|
||||
case PermittedProcess::Wireguard:
|
||||
return Utils::wireguardExecPath();
|
||||
case PermittedProcess::CertUtil:
|
||||
return Utils::certUtilPath();
|
||||
case PermittedProcess::Tun2Socks:
|
||||
return Utils::tun2socksPath();
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +51,51 @@ inline QString getIpcProcessUrl(int pid) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline QStringList sanitizeArguments(PermittedProcess proc, const QStringList &args) {
|
||||
using Validator = std::function<bool(const QString&)>;
|
||||
QMap<QString, Validator> namedArgs;
|
||||
QList<Validator> positionalArgs;
|
||||
|
||||
switch (proc) {
|
||||
case Tun2Socks:
|
||||
namedArgs["-device"] = [](const QString& v) { return v.startsWith("tun://"); };
|
||||
namedArgs["-proxy"] = [](const QString& v) { return v.startsWith("socks5://"); };
|
||||
break;
|
||||
default:
|
||||
//FIXME
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
QStringList sanitized;
|
||||
|
||||
for (int i = 0, pos = 0; i < args.size(); i++) {
|
||||
const auto& key = args[i];
|
||||
|
||||
if (const auto found = namedArgs.find(key); found != namedArgs.end()) {
|
||||
const auto validator = found.value();
|
||||
|
||||
if (validator) {
|
||||
if (i + 1 < args.size()) {
|
||||
const auto& value = args[i+1];
|
||||
if (validator(value)) {
|
||||
sanitized << key << value;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sanitized << key;
|
||||
}
|
||||
} else if (pos < positionalArgs.size()) {
|
||||
if (const auto validator = positionalArgs[pos]; validator && validator(key)) {
|
||||
sanitized << key;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
} // namespace amnezia
|
||||
|
||||
|
||||
@@ -38,12 +38,13 @@ class IpcInterface
|
||||
SLOT( bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) );
|
||||
SLOT( bool restoreResolvers() );
|
||||
|
||||
SLOT(void xrayStart(const QString &config));
|
||||
SLOT(void xrayStop());
|
||||
SLOT(bool xrayStart(const QString &config));
|
||||
SLOT(bool xrayStop());
|
||||
|
||||
SLOT( bool startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address) );
|
||||
SLOT( bool stopNetworkCheck() );
|
||||
|
||||
SIGNAL( connectionLose() );
|
||||
SIGNAL( networkChange() );
|
||||
SIGNAL( wakeup() );
|
||||
SIGNAL( networkChanged() );
|
||||
};
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
class IpcProcessInterface
|
||||
{
|
||||
SLOT( start() );
|
||||
SLOT( terminate() );
|
||||
SLOT( kill() );
|
||||
SLOT( close() );
|
||||
|
||||
SLOT( setArguments(const QStringList &arguments) );
|
||||
@@ -17,6 +19,11 @@ class IpcProcessInterface
|
||||
SLOT( QByteArray readAllStandardError() );
|
||||
SLOT( QByteArray readAllStandardOutput() );
|
||||
|
||||
SLOT( bool waitForFinished() );
|
||||
SLOT( bool waitForFinished(int msecs) );
|
||||
SLOT( bool waitForStarted() );
|
||||
SLOT( bool waitForStarted(int msecs) );
|
||||
|
||||
|
||||
SIGNAL( errorOccurred(QProcess::ProcessError error) );
|
||||
SIGNAL( finished(int exitCode, QProcess::ExitStatus exitStatus) );
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#include <QtCore>
|
||||
#include <QString>
|
||||
|
||||
class IpcProcessTun2Socks
|
||||
{
|
||||
SLOT( start() );
|
||||
SLOT( stop() );
|
||||
|
||||
SIGNAL( setConnectionState(int state) );
|
||||
SIGNAL( stateChanged(QProcess::ProcessState newState) );
|
||||
};
|
||||
@@ -304,7 +304,7 @@ bool IpcServer::refreshKillSwitch(bool enabled)
|
||||
return KillSwitch::instance()->refresh(enabled);
|
||||
}
|
||||
|
||||
void IpcServer::xrayStart(const QString& cfg)
|
||||
bool IpcServer::xrayStart(const QString& cfg)
|
||||
{
|
||||
#ifdef MZ_DEBUG
|
||||
qDebug() << "IpcServer::xrayStart";
|
||||
@@ -313,7 +313,7 @@ void IpcServer::xrayStart(const QString& cfg)
|
||||
return Xray::getInstance().startXray(cfg);
|
||||
}
|
||||
|
||||
void IpcServer::xrayStop()
|
||||
bool IpcServer::xrayStop()
|
||||
{
|
||||
#ifdef MZ_DEBUG
|
||||
qDebug() << "IpcServer::xrayStop";
|
||||
|
||||
@@ -10,10 +10,8 @@
|
||||
|
||||
#include "ipc.h"
|
||||
#include "ipcserverprocess.h"
|
||||
#include "ipctun2socksprocess.h"
|
||||
|
||||
#include "rep_ipc_interface_source.h"
|
||||
#include "rep_ipc_process_tun2socks_source.h"
|
||||
|
||||
class IpcServer : public IpcInterfaceSource
|
||||
{
|
||||
@@ -44,8 +42,8 @@ public:
|
||||
virtual bool refreshKillSwitch( bool enabled ) override;
|
||||
virtual bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) override;
|
||||
virtual bool restoreResolvers() override;
|
||||
virtual void xrayStart(const QString& cfg) override;
|
||||
virtual void xrayStop() override;
|
||||
virtual bool xrayStart(const QString& cfg) override;
|
||||
virtual bool xrayStop() override;
|
||||
virtual bool startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address) override;
|
||||
virtual bool stopNetworkCheck() override;
|
||||
|
||||
@@ -56,12 +54,10 @@ private:
|
||||
ProcessDescriptor (QObject *parent = nullptr) {
|
||||
serverNode = QSharedPointer<QRemoteObjectHost>(new QRemoteObjectHost(parent));
|
||||
ipcProcess = QSharedPointer<IpcServerProcess>(new IpcServerProcess(parent));
|
||||
tun2socksProcess = QSharedPointer<IpcProcessTun2Socks>(new IpcProcessTun2Socks(parent));
|
||||
localServer = QSharedPointer<QLocalServer>(new QLocalServer(parent));
|
||||
}
|
||||
|
||||
QSharedPointer<IpcServerProcess> ipcProcess;
|
||||
QSharedPointer<IpcProcessTun2Socks> tun2socksProcess;
|
||||
QSharedPointer<QRemoteObjectHost> serverNode;
|
||||
QSharedPointer<QLocalServer> localServer;
|
||||
};
|
||||
|
||||
@@ -40,6 +40,14 @@ void IpcServerProcess::start()
|
||||
m_process->waitForStarted();
|
||||
}
|
||||
|
||||
void IpcServerProcess::terminate() {
|
||||
m_process->terminate();
|
||||
}
|
||||
|
||||
void IpcServerProcess::kill() {
|
||||
m_process->kill();
|
||||
}
|
||||
|
||||
void IpcServerProcess::close()
|
||||
{
|
||||
m_process->close();
|
||||
@@ -47,7 +55,7 @@ void IpcServerProcess::close()
|
||||
|
||||
void IpcServerProcess::setArguments(const QStringList &arguments)
|
||||
{
|
||||
m_process->setArguments(arguments);
|
||||
m_process->setArguments(amnezia::sanitizeArguments(m_program, arguments));
|
||||
}
|
||||
|
||||
void IpcServerProcess::setInputChannelMode(QProcess::InputChannelMode mode)
|
||||
@@ -69,7 +77,9 @@ void IpcServerProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode)
|
||||
|
||||
void IpcServerProcess::setProgram(int programId)
|
||||
{
|
||||
m_process->setProgram(amnezia::permittedProcessPath(static_cast<amnezia::PermittedProcess>(programId)));
|
||||
m_program = static_cast<amnezia::PermittedProcess>(programId);
|
||||
m_process->setProgram(amnezia::permittedProcessPath(m_program));
|
||||
m_process->setArguments({});
|
||||
}
|
||||
|
||||
void IpcServerProcess::setWorkingDirectory(const QString &dir)
|
||||
@@ -92,4 +102,20 @@ QByteArray IpcServerProcess::readAllStandardOutput()
|
||||
return m_process->readAllStandardOutput();
|
||||
}
|
||||
|
||||
bool IpcServerProcess::waitForStarted() {
|
||||
return m_process->waitForStarted();
|
||||
}
|
||||
|
||||
bool IpcServerProcess::waitForStarted(int msecs) {
|
||||
return m_process->waitForStarted(msecs);
|
||||
}
|
||||
|
||||
bool IpcServerProcess::waitForFinished() {
|
||||
return m_process->waitForFinished();
|
||||
}
|
||||
|
||||
bool IpcServerProcess::waitForFinished(int msecs) {
|
||||
return m_process->waitForFinished(msecs);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef IPCSERVERPROCESS_H
|
||||
#define IPCSERVERPROCESS_H
|
||||
|
||||
#include "ipc.h"
|
||||
#include <QObject>
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
@@ -14,6 +15,8 @@ public:
|
||||
virtual ~IpcServerProcess();
|
||||
|
||||
void start() override;
|
||||
void terminate() override;
|
||||
void kill() override;
|
||||
void close() override;
|
||||
|
||||
void setArguments(const QStringList &arguments) override;
|
||||
@@ -27,9 +30,15 @@ public:
|
||||
QByteArray readAllStandardError() override;
|
||||
QByteArray readAllStandardOutput() override;
|
||||
|
||||
bool waitForStarted() override;
|
||||
bool waitForStarted(int msecs) override;
|
||||
bool waitForFinished() override;
|
||||
bool waitForFinished(int msecs) override;
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
amnezia::PermittedProcess m_program = amnezia::PermittedProcess::Invalid;
|
||||
QSharedPointer<QProcess> m_process;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#include "ipctun2socksprocess.h"
|
||||
#include "ipc.h"
|
||||
#include <QProcess>
|
||||
#include <QString>
|
||||
|
||||
#include "../protocols/protocols_defs.h"
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
|
||||
IpcProcessTun2Socks::IpcProcessTun2Socks(QObject *parent) :
|
||||
IpcProcessTun2SocksSource(parent),
|
||||
m_t2sProcess(QSharedPointer<QProcess>(new QProcess()))
|
||||
{
|
||||
qDebug() << "IpcProcessTun2Socks::IpcProcessTun2Socks()";
|
||||
|
||||
}
|
||||
|
||||
IpcProcessTun2Socks::~IpcProcessTun2Socks()
|
||||
{
|
||||
qDebug() << "IpcProcessTun2Socks::~IpcProcessTun2Socks()";
|
||||
}
|
||||
|
||||
void IpcProcessTun2Socks::start()
|
||||
{
|
||||
connect(m_t2sProcess.data(), &QProcess::stateChanged, this, &IpcProcessTun2Socks::stateChanged);
|
||||
qDebug() << "IpcProcessTun2Socks::start()";
|
||||
m_t2sProcess->setProgram(amnezia::permittedProcessPath(static_cast<amnezia::PermittedProcess>(amnezia::PermittedProcess::Tun2Socks)));
|
||||
|
||||
QString XrayConStr = "socks5://127.0.0.1:10808";
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QStringList arguments({"-device", "tun://tun2?guid={081A8A84-8D12-4DF5-B8C4-396D5B0053E4}", "-proxy", XrayConStr });
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr});
|
||||
#endif
|
||||
#ifdef Q_OS_MAC
|
||||
QStringList arguments({"-device", "utun22", "-proxy", XrayConStr});
|
||||
#endif
|
||||
|
||||
m_t2sProcess->setArguments(arguments);
|
||||
|
||||
if (Utils::processIsRunning(Utils::executable("tun2socks", false))) {
|
||||
qDebug().noquote() << "kill previos tun2socks";
|
||||
Utils::killProcessByName(Utils::executable("tun2socks", false));
|
||||
}
|
||||
|
||||
connect(m_t2sProcess.data(), &QProcess::readyReadStandardOutput, this, [this]() {
|
||||
QString line = m_t2sProcess.data()->readAllStandardOutput();
|
||||
if (line.contains("[STACK] tun://") && line.contains("<-> socks5://127.0.0.1")) {
|
||||
emit setConnectionState(Vpn::ConnectionState::Connected);
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_t2sProcess.data(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
qDebug().noquote() << "tun2socks finished, exitCode, exiStatus" << exitCode << exitStatus;
|
||||
emit setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
if ((exitStatus != QProcess::NormalExit) || (exitCode != 0)) {
|
||||
emit setConnectionState(Vpn::ConnectionState::Error);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
m_t2sProcess->start();
|
||||
m_t2sProcess->waitForStarted();
|
||||
}
|
||||
|
||||
void IpcProcessTun2Socks::stop()
|
||||
{
|
||||
qDebug() << "IpcProcessTun2Socks::stop()";
|
||||
m_t2sProcess->disconnect();
|
||||
m_t2sProcess->kill();
|
||||
m_t2sProcess->waitForFinished(3000);
|
||||
}
|
||||
#endif
|
||||
@@ -1,52 +0,0 @@
|
||||
#ifndef IPCTUN2SOCKSPROCESS_H
|
||||
#define IPCTUN2SOCKSPROCESS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
#include "rep_ipc_process_tun2socks_source.h"
|
||||
|
||||
namespace Vpn
|
||||
{
|
||||
Q_NAMESPACE
|
||||
enum ConnectionState {
|
||||
Unknown,
|
||||
Disconnected,
|
||||
Preparing,
|
||||
Connecting,
|
||||
Connected,
|
||||
Disconnecting,
|
||||
Reconnecting,
|
||||
Error
|
||||
};
|
||||
Q_ENUM_NS(ConnectionState)
|
||||
}
|
||||
|
||||
|
||||
class IpcProcessTun2Socks : public IpcProcessTun2SocksSource
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IpcProcessTun2Socks(QObject *parent = nullptr);
|
||||
virtual ~IpcProcessTun2Socks();
|
||||
|
||||
void start() override;
|
||||
void stop() override;
|
||||
|
||||
signals:
|
||||
|
||||
private:
|
||||
QSharedPointer<QProcess> m_t2sProcess;
|
||||
};
|
||||
|
||||
#else
|
||||
class IpcProcessTun2Socks : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit IpcProcessTun2Socks(QObject *parent = nullptr);
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // IPCTUN2SOCKSPROCESS_H
|
||||
48
recipes/amnezia-libxray/conanfile.py
Normal file
48
recipes/amnezia-libxray/conanfile.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from conan import ConanFile
|
||||
from conan.tools.files import get, copy
|
||||
from conan.tools.layout import basic_layout
|
||||
from conan.errors import ConanInvalidConfiguration
|
||||
|
||||
import os
|
||||
import stat
|
||||
|
||||
class AmneziaLibxray(ConanFile):
|
||||
name = "amnezia-libxray"
|
||||
version = "1.0.0"
|
||||
|
||||
settings = "os", "arch"
|
||||
options = {"page_16k": [True, False]}
|
||||
default_options = {"page_16k": True}
|
||||
|
||||
def layout(self):
|
||||
basic_layout(self, build_folder=".")
|
||||
|
||||
def build_requirements(self):
|
||||
self.tool_requires("go/1.26.0")
|
||||
|
||||
def validate(self):
|
||||
if self.settings.os != "Android":
|
||||
raise ConanInvalidConfiguration(f"{self.name} v{self.version} does not support {self.settings.os}")
|
||||
|
||||
def source(self):
|
||||
get(self, "https://github.com/amnezia-vpn/amnezia-libxray/archive/refs/tags/v1.0.0.zip",
|
||||
sha256="0c50c5acd5063a9fc3cfbb5b3e11481d30cfa3762b3cb1d72130248ff498e9df", strip_root=True
|
||||
)
|
||||
|
||||
def _patch_sources(self):
|
||||
build_path = os.path.join(self.build_folder, "build.sh")
|
||||
build_stat = os.stat(build_path)
|
||||
os.chmod(build_path, build_stat.st_mode | stat.S_IEXEC)
|
||||
|
||||
def build(self):
|
||||
self._patch_sources()
|
||||
cgo_ldflags = 'CGO_LDFLAGS="-Wl,-z,max-page-size=16384" ' if self.options.page_16k else ""
|
||||
self.run(f'{cgo_ldflags}./build.sh android')
|
||||
|
||||
def package(self):
|
||||
copy(self, "libxray.aar", src=self.build_folder, dst=os.path.join(self.package_folder, "aar"))
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.set_property("cmake_extra_variables", {
|
||||
"AMNEZIA_LIBXRAY_PATH": os.path.join(self.package_folder, "aar", "libxray.aar"),
|
||||
})
|
||||
90
recipes/amnezia-xray-bindings/conanfile.py
Normal file
90
recipes/amnezia-xray-bindings/conanfile.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# conanfile.py
|
||||
from conan import ConanFile
|
||||
from conan.tools.files import get, copy, collect_libs, chdir
|
||||
from conan.tools.layout import basic_layout
|
||||
from conan.errors import ConanInvalidConfiguration
|
||||
from conan.tools.gnu import Autotools, AutotoolsToolchain
|
||||
from conan.tools.env import Environment
|
||||
|
||||
import os
|
||||
|
||||
class AmneziaXrayBindings(ConanFile):
|
||||
name = "amnezia-xray-bindings"
|
||||
version = "1.1.0"
|
||||
|
||||
settings = "os", "arch"
|
||||
|
||||
@property
|
||||
def _goos(self):
|
||||
return {
|
||||
"Linux": "linux",
|
||||
"iOS": "ios",
|
||||
"Macos": "darwin",
|
||||
"Windows": "windows"
|
||||
}.get(str(self.settings.os))
|
||||
|
||||
@property
|
||||
def _goarch(self):
|
||||
return {
|
||||
"x86": "386",
|
||||
"x86_64": "amd64",
|
||||
"armv8": "arm64"
|
||||
}.get(str(self.settings.arch))
|
||||
|
||||
@property
|
||||
def _is_windows(self):
|
||||
return str(self.settings.os).startswith("Windows")
|
||||
|
||||
def validate(self):
|
||||
if not self._goos or not self._goarch:
|
||||
raise ConanInvalidConfiguration(
|
||||
f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}"
|
||||
)
|
||||
|
||||
def layout(self):
|
||||
basic_layout(self)
|
||||
|
||||
def build_requirements(self):
|
||||
self.tool_requires("go/1.26.0")
|
||||
|
||||
def source(self):
|
||||
get(self, "https://github.com/amnezia-vpn/amnezia-xray-bindings/archive/v1.1.0.zip",
|
||||
sha256="6ea768ec7002cedd422a39aea17704b888acaf794432aa5937cfc92fb6d80eb5", strip_root=True)
|
||||
|
||||
def generate(self):
|
||||
tc = AutotoolsToolchain(self)
|
||||
env = Environment()
|
||||
env.define("ARCH", self._goarch)
|
||||
env.define("GOARCH", self._goarch)
|
||||
env.define("GOOS", self._goos)
|
||||
env.define("CGO_LDFLAGS", tc.ldflags)
|
||||
env.define("CGO_CFLAGS", tc.cflags)
|
||||
if self._is_windows:
|
||||
env.define("OS", "windows")
|
||||
tc.generate(env)
|
||||
|
||||
def build(self):
|
||||
with chdir(self, self.source_folder):
|
||||
autotools = Autotools(self)
|
||||
autotools.make()
|
||||
|
||||
def _rename_libs(self):
|
||||
# workaround of bad naming strategy in amnezia-xray-bindings
|
||||
# TODO: change it and kick out the code below
|
||||
lib_dir = os.path.join(self.package_folder, "lib")
|
||||
for fname in os.listdir(lib_dir):
|
||||
if not fname.startswith("lib"):
|
||||
src = os.path.join(lib_dir, fname)
|
||||
dst = os.path.join(lib_dir, "lib" + fname)
|
||||
os.rename(src, dst)
|
||||
|
||||
def package(self):
|
||||
copy(self, "*.h", src=self.build_folder, dst=os.path.join(self.package_folder, "include"))
|
||||
copy(self, "*.a", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"))
|
||||
copy(self, "*.dll", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"))
|
||||
copy(self, "*.lib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"))
|
||||
self._rename_libs()
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.set_property("cmake_target_name", "amnezia::xray-bindings")
|
||||
self.cpp_info.libs = collect_libs(self)
|
||||
131
recipes/android-openssl/conanfile.py
Normal file
131
recipes/android-openssl/conanfile.py
Normal file
@@ -0,0 +1,131 @@
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shutil
|
||||
|
||||
from conan import ConanFile
|
||||
from conan.tools.files import copy
|
||||
from conan.tools.scm import Git
|
||||
from conan.errors import ConanInvalidConfiguration, ConanException
|
||||
|
||||
|
||||
class AndroidOpenSSL(ConanFile):
|
||||
name = "android-openssl"
|
||||
version = "3.5.5"
|
||||
settings = "os", "arch"
|
||||
options = {"page_16k": [True, False]}
|
||||
default_options = {"page_16k": True}
|
||||
|
||||
# Conan arch → OpenSSL Configure target
|
||||
_arch_map = {
|
||||
"armv8": "android-arm64",
|
||||
"armv7": "android-arm",
|
||||
"x86_64": "android-x86_64",
|
||||
"x86": "android-x86",
|
||||
}
|
||||
|
||||
def validate(self):
|
||||
if self.settings.os != "Android":
|
||||
raise ConanInvalidConfiguration(f"{self.name} only supports Android")
|
||||
if str(self.settings.arch) not in self._arch_map:
|
||||
raise ConanInvalidConfiguration(f"Unsupported arch: {self.settings.arch}")
|
||||
|
||||
def source(self):
|
||||
git = Git(self)
|
||||
git.clone(
|
||||
url="https://github.com/openssl/openssl.git",
|
||||
target=".",
|
||||
args=["--branch", f"openssl-{self.version}", "--depth", "1"]
|
||||
)
|
||||
|
||||
def _ndk(self):
|
||||
ndk = self.conf.get("tools.android:ndk_path", check_type=str) or \
|
||||
os.environ.get("ANDROID_NDK_ROOT", "")
|
||||
if not ndk:
|
||||
raise ConanException(
|
||||
"Android NDK not found. Set tools.android:ndk_path conf or ANDROID_NDK_ROOT env."
|
||||
)
|
||||
return ndk
|
||||
|
||||
def _toolchain_bin(self):
|
||||
host = "linux-x86_64" if platform.system() == "Linux" else "darwin-x86_64"
|
||||
return os.path.join(self._ndk(), "toolchains", "llvm", "prebuilt", host, "bin")
|
||||
|
||||
def _patch_makefile(self, makefile_path, page_16k=False):
|
||||
"""Rename libcrypto.so → libcrypto_3.so and libssl.so → libssl_3.so
|
||||
throughout the generated Makefile so the built files already carry the
|
||||
correct names and sonames — no patchelf required.
|
||||
Optionally append the 16KB page-size linker flag to LDFLAGS."""
|
||||
with open(makefile_path, "r") as f:
|
||||
content = f.read()
|
||||
|
||||
# Replace every standalone libcrypto.so / libssl.so reference.
|
||||
# \b word-boundary keeps us from matching libcrypto.so.3 style names.
|
||||
content = re.sub(r"\blibcrypto\.so\b", "libcrypto_3.so", content)
|
||||
content = re.sub(r"\blibssl\.so\b", "libssl_3.so", content)
|
||||
|
||||
if page_16k:
|
||||
page_flag = "-Wl,-z,max-page-size=16384"
|
||||
content = re.sub(
|
||||
r"^(LDFLAGS\s*=)(.*?)$",
|
||||
lambda m: m.group(0) + " " + page_flag if page_flag not in m.group(0) else m.group(0),
|
||||
content,
|
||||
flags=re.MULTILINE,
|
||||
)
|
||||
|
||||
with open(makefile_path, "w") as f:
|
||||
f.write(content)
|
||||
|
||||
def build(self):
|
||||
ndk = self._ndk()
|
||||
toolchain_bin = self._toolchain_bin()
|
||||
target = self._arch_map[str(self.settings.arch)]
|
||||
api_level = str(self.settings.os.api_level)
|
||||
jobs = os.cpu_count() or 4
|
||||
|
||||
env_prefix = f'PATH="{toolchain_bin}:$PATH" ANDROID_NDK_ROOT="{ndk}"'
|
||||
|
||||
configure_cmd = (
|
||||
f"./Configure {target} shared no-tests"
|
||||
f" -D__ANDROID_API__={api_level}"
|
||||
)
|
||||
|
||||
self.run(f"{env_prefix} {configure_cmd}", cwd=self.source_folder)
|
||||
|
||||
self._patch_makefile(
|
||||
os.path.join(self.source_folder, "Makefile"),
|
||||
page_16k=bool(self.options.page_16k),
|
||||
)
|
||||
|
||||
self.run(
|
||||
f"{env_prefix} make -j{jobs} SHLIB_VERSION_NUMBER= build_libs",
|
||||
cwd=self.source_folder
|
||||
)
|
||||
|
||||
def package(self):
|
||||
lib_dst = os.path.join(self.package_folder, "lib")
|
||||
os.makedirs(lib_dst, exist_ok=True)
|
||||
|
||||
copy(self, "libcrypto_3.so", src=self.source_folder, dst=lib_dst, keep_path=False)
|
||||
copy(self, "libssl_3.so", src=self.source_folder, dst=lib_dst, keep_path=False)
|
||||
|
||||
# Static libs (still named without suffix)
|
||||
copy(self, "libcrypto.a", src=self.source_folder, dst=lib_dst, keep_path=False)
|
||||
copy(self, "libssl.a", src=self.source_folder, dst=lib_dst, keep_path=False)
|
||||
|
||||
# Headers
|
||||
copy(self, "include/openssl/*.h", src=self.source_folder, dst=self.package_folder)
|
||||
|
||||
def package_info(self):
|
||||
# Expose the same CMake targets as the upstream openssl package so
|
||||
# consumers (libssh, main app) need no changes to their target_link_libraries.
|
||||
self.cpp_info.components["crypto"].set_property("cmake_target_name", "OpenSSL::Crypto")
|
||||
self.cpp_info.components["crypto"].libs = ["crypto_3"]
|
||||
self.cpp_info.components["crypto"].includedirs = ["include"]
|
||||
self.cpp_info.components["crypto"].libdirs = ["lib"]
|
||||
|
||||
self.cpp_info.components["ssl"].set_property("cmake_target_name", "OpenSSL::SSL")
|
||||
self.cpp_info.components["ssl"].libs = ["ssl_3"]
|
||||
self.cpp_info.components["ssl"].includedirs = []
|
||||
self.cpp_info.components["ssl"].libdirs = ["lib"]
|
||||
self.cpp_info.components["ssl"].requires = ["crypto"]
|
||||
94
recipes/awg-android/conanfile.py
Normal file
94
recipes/awg-android/conanfile.py
Normal file
@@ -0,0 +1,94 @@
|
||||
from conan import ConanFile
|
||||
from conan.tools.cmake import cmake_layout, CMake, CMakeToolchain
|
||||
from conan.tools.env import VirtualBuildEnv
|
||||
from conan.tools.files import copy, replace_in_file
|
||||
from conan.errors import ConanInvalidConfiguration
|
||||
from conan.tools.scm import Git
|
||||
|
||||
import os
|
||||
import platform
|
||||
|
||||
class AwgAndroid(ConanFile):
|
||||
name = "awg-android"
|
||||
version = "1.1.7"
|
||||
settings = "os", "arch", "build_type", "compiler"
|
||||
package_type = "shared-library"
|
||||
options = {"page_16k": [True, False]}
|
||||
default_options = {"page_16k": True}
|
||||
|
||||
def layout(self):
|
||||
cmake_layout(self)
|
||||
|
||||
def build_requirements(self):
|
||||
self.tool_requires("cmake/[>=3.4.1 <4]")
|
||||
|
||||
def validate(self):
|
||||
if self.settings.os != "Android":
|
||||
raise ConanInvalidConfiguration(f"{self.name} v{self.version} does not support {self.settings.os}")
|
||||
|
||||
def source(self):
|
||||
git = Git(self)
|
||||
git.clone(
|
||||
url="https://github.com/amnezia-vpn/amneziawg-android.git",
|
||||
target=".",
|
||||
args=["--recurse-submodules", "--branch", f"v{self.version}"]
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
tc = CMakeToolchain(self)
|
||||
tc.variables["GRADLE_USER_HOME"] = os.path.join(self.build_folder, "gradle_user_home")
|
||||
tc.variables["CMAKE_LIBRARY_OUTPUT_DIRECTORY"] = os.path.join(self.build_folder, "out")
|
||||
if self.options.page_16k:
|
||||
# Use cache_variables to override NDK toolchain defaults (extra_ldflags sets _INIT
|
||||
# variants which the NDK toolchain can override). CMAKE_SHARED_LINKER_FLAGS is passed
|
||||
# directly to the Go Makefile as LDFLAGS, which flows into CGO_LDFLAGS.
|
||||
page_flag = "-Wl,-z,max-page-size=16384"
|
||||
tc.cache_variables["CMAKE_EXE_LINKER_FLAGS"] = page_flag
|
||||
tc.cache_variables["CMAKE_SHARED_LINKER_FLAGS"] = page_flag
|
||||
tc.generate()
|
||||
|
||||
vbe = VirtualBuildEnv(self)
|
||||
vbe.generate()
|
||||
|
||||
def _patch_sources(self):
|
||||
if platform.system() == 'Darwin':
|
||||
replace_in_file(self,
|
||||
os.path.join(self.source_folder, "tunnel", "tools", "libwg-go", "Makefile"),
|
||||
'flock "$@.lock" -c \' \\\n',
|
||||
"",
|
||||
)
|
||||
replace_in_file(self,
|
||||
os.path.join(self.source_folder, "tunnel", "tools", "libwg-go", "Makefile"),
|
||||
'mv "$@.tmp" "$@"\'',
|
||||
'mv "$@.tmp" "$@"',
|
||||
)
|
||||
replace_in_file(self,
|
||||
os.path.join(self.source_folder, "tunnel", "tools", "libwg-go", "Makefile"),
|
||||
'touch "$@"\'',
|
||||
'touch "$@"',
|
||||
)
|
||||
replace_in_file(self,
|
||||
os.path.join(self.source_folder, "tunnel", "tools", "libwg-go", "Makefile"),
|
||||
'sha256sum -c',
|
||||
'shasum -a 256 -c'
|
||||
)
|
||||
|
||||
def build(self):
|
||||
self._patch_sources()
|
||||
cmake = CMake(self)
|
||||
cmake.configure(build_script_folder=os.path.join(self.source_folder, "tunnel", "tools"))
|
||||
cmake.build(target=["libwg-go.so", "libwg.so", "libwg-quick.so"])
|
||||
|
||||
def package(self):
|
||||
copy(self, "libwg-go.h", src=os.path.join(self.build_folder, "out"), dst=os.path.join(self.package_folder, "include"))
|
||||
copy(self, "libwg-go.so", src=os.path.join(self.build_folder, "out"), dst=os.path.join(self.package_folder, "lib"))
|
||||
copy(self, "libwg.so", src=os.path.join(self.build_folder, "out"), dst=os.path.join(self.package_folder, "bin"))
|
||||
copy(self, "libwg-quick.so", src=os.path.join(self.build_folder, "out"), dst=os.path.join(self.package_folder, "bin"))
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.set_property("cmake_target_name", "amnezia::awg-android")
|
||||
self.cpp_info.libs = [ "wg-go" ]
|
||||
self.cpp_info.set_property("cmake_extra_variables", {
|
||||
"AMNEZIA_ANDROID_LIBWG_PATH": os.path.join(self.package_folder, "bin", "libwg.so"),
|
||||
"AMNEZIA_ANDROID_LIBWG_QUICK_PATH": os.path.join(self.package_folder, "bin", "libwg-quick.so"),
|
||||
})
|
||||
68
recipes/awg-apple/conanfile.py
Normal file
68
recipes/awg-apple/conanfile.py
Normal file
@@ -0,0 +1,68 @@
|
||||
from conan import ConanFile
|
||||
from conan.errors import ConanInvalidConfiguration
|
||||
from conan.tools.layout import basic_layout
|
||||
from conan.tools.files import get, copy, collect_libs, chdir
|
||||
from conan.tools.apple import is_apple_os
|
||||
from conan.tools.gnu import AutotoolsToolchain, Autotools
|
||||
|
||||
import os
|
||||
|
||||
class AwgApple(ConanFile):
|
||||
name = "awg-apple"
|
||||
version = "2.0.1"
|
||||
settings = "os", "arch"
|
||||
options = {
|
||||
"as_framework": [True, False]
|
||||
}
|
||||
default_options = {
|
||||
"as_framework": False
|
||||
}
|
||||
|
||||
@property
|
||||
def _goarch(self):
|
||||
arch_map = {
|
||||
"armv8": "arm64",
|
||||
"x86_64": "x86_64",
|
||||
}
|
||||
archs = str(self.settings.arch).split("|")
|
||||
return " ".join(arch_map.get(arch, arch) for arch in archs)
|
||||
|
||||
def build_requirements(self):
|
||||
self.tool_requires("go/1.26.0")
|
||||
|
||||
def layout(self):
|
||||
basic_layout(self, build_folder=os.path.join(self.folders.source, "Sources/WireGuardKitGo"))
|
||||
|
||||
def validate(self):
|
||||
if not is_apple_os(self):
|
||||
raise ConanInvalidConfiguration(
|
||||
f"{self.name} v{self.version} does not support {self.settings.os}"
|
||||
)
|
||||
|
||||
def source(self):
|
||||
get(self, f"https://github.com/amnezia-vpn/amneziawg-apple/archive/refs/tags/v{self.version}.zip",
|
||||
sha256="9fe4f8cfbb6a751558b54b7979db3a5ea46e49731912aae99f093e84a1433e97", strip_root=True
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
tc = AutotoolsToolchain(self)
|
||||
sdk = self.settings.get_safe("os.sdk", "macosx")
|
||||
tc.make_args = [
|
||||
f"ARCHS={self._goarch}",
|
||||
f"PLATFORM_NAME={sdk}"
|
||||
]
|
||||
tc.generate()
|
||||
|
||||
def build(self):
|
||||
autotools = Autotools(self)
|
||||
autotools.make()
|
||||
autotools.make("version-header")
|
||||
|
||||
def package(self):
|
||||
copy(self, "wireguard.h", src=self.build_folder, dst=os.path.join(self.package_folder, "include"))
|
||||
copy(self, "*.h", src=os.path.join(self.build_folder, "out"), dst=os.path.join(self.package_folder, "include"))
|
||||
copy(self, "*.a", src=os.path.join(self.build_folder, "out"), dst=os.path.join(self.package_folder, "lib"))
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.set_property("cmake_target_name", "amnezia::awg-apple")
|
||||
self.cpp_info.libs = collect_libs(self)
|
||||
66
recipes/awg-go/conanfile.py
Normal file
66
recipes/awg-go/conanfile.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from conan import ConanFile
|
||||
from conan.errors import ConanInvalidConfiguration
|
||||
from conan.tools.layout import basic_layout
|
||||
from conan.tools.files import get, copy
|
||||
from conan.tools.gnu import Autotools, AutotoolsToolchain
|
||||
from conan.tools.env import Environment
|
||||
|
||||
import os
|
||||
|
||||
class AwgGo(ConanFile):
|
||||
name = "awg-go"
|
||||
version = "0.2.16"
|
||||
package_type = "application"
|
||||
settings = "os", "arch"
|
||||
|
||||
@property
|
||||
def _goos(self):
|
||||
return {
|
||||
"Linux": "linux",
|
||||
"Macos": "darwin",
|
||||
"Windows": "windows"
|
||||
}.get(str(self.settings.os))
|
||||
|
||||
@property
|
||||
def _goarch(self):
|
||||
return {
|
||||
"x86": "386",
|
||||
"x86_64": "amd64",
|
||||
"armv8": "arm64"
|
||||
}.get(str(self.settings.arch))
|
||||
|
||||
def build_requirements(self):
|
||||
self.tool_requires("go/1.26.0")
|
||||
|
||||
def validate(self):
|
||||
if not self._goos or not self._goarch:
|
||||
raise ConanInvalidConfiguration(
|
||||
f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}"
|
||||
)
|
||||
|
||||
def source(self):
|
||||
get(self, f"https://github.com/amnezia-vpn/amneziawg-go/archive/refs/tags/v{self.version}.zip",
|
||||
sha256="34da7d4189f215f3930de441548bc2a0c89d54d347a4fb85cb9c715fce6413aa", strip_root=True
|
||||
)
|
||||
|
||||
def layout(self):
|
||||
basic_layout(self, build_folder=".")
|
||||
|
||||
def generate(self):
|
||||
tc = AutotoolsToolchain(self)
|
||||
env = Environment()
|
||||
env.define("GOOS", self._goos)
|
||||
env.define("GOARCH", self._goarch)
|
||||
tc.generate(env)
|
||||
|
||||
def build(self):
|
||||
at = Autotools(self)
|
||||
at.make()
|
||||
|
||||
def package(self):
|
||||
copy(self, "amneziawg-go", src=self.build_folder, dst=self.package_folder)
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.exe = True
|
||||
self.cpp_info.location = os.path.join(self.package_folder, "amneziawg-go")
|
||||
self.cpp_info.set_property("cmake_target_name", "amnezia::awg-go")
|
||||
0
recipes/awg-windows/conanfile.py
Normal file
0
recipes/awg-windows/conanfile.py
Normal file
26
recipes/go/conandata.yml
Normal file
26
recipes/go/conandata.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
sources:
|
||||
"1.26.0":
|
||||
Macos:
|
||||
x86_64:
|
||||
url: "https://go.dev/dl/go1.26.0.darwin-amd64.tar.gz"
|
||||
sha256: "1ca28b7703cbea05a65b2a1d92d6b308610ef92f8824578a0874f2e60c9d5a22"
|
||||
armv8:
|
||||
url: "https://go.dev/dl/go1.26.0.darwin-arm64.tar.gz"
|
||||
sha256: "b1640525dfe68f066d56f200bef7bf4dce955a1a893bd061de6754c211431023"
|
||||
Linux:
|
||||
x86:
|
||||
url: "https://go.dev/dl/go1.26.0.linux-386.tar.gz"
|
||||
sha256: "35e2ec7a7ae6905a1fae5459197b70e3fcbc5e0a786a7d6ba8e49bcd38ad2e26"
|
||||
x86_64:
|
||||
url: "https://go.dev/dl/go1.26.0.linux-amd64.tar.gz"
|
||||
sha256: "aac1b08a0fb0c4e0a7c1555beb7b59180b05dfc5a3d62e40e9de90cd42f88235"
|
||||
armv8:
|
||||
url: "https://go.dev/dl/go1.26.0.linux-arm64.tar.gz"
|
||||
sha256: "bd03b743eb6eb4193ea3c3fd3956546bf0e3ca5b7076c8226334afe6b75704cd"
|
||||
Windows:
|
||||
x86:
|
||||
url: "https://go.dev/dl/go1.26.0.windows-386.zip"
|
||||
sha256: "50674f3d6a071fa1a4c1d76dc37fafa0330df87d84087a262fee020da5396b6b"
|
||||
x86_64:
|
||||
url: "https://go.dev/dl/go1.26.0.windows-amd64.zip"
|
||||
sha256: "9bbe0fc64236b2b51f6255c05c4232532b8ecc0e6d2e00950bd3021d8a4d07d4"
|
||||
19
recipes/go/conanfile.py
Normal file
19
recipes/go/conanfile.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from conan import ConanFile
|
||||
from conan.tools.files import get, copy
|
||||
|
||||
import os
|
||||
|
||||
class Golang(ConanFile):
|
||||
name = "go"
|
||||
version = "1.26.0"
|
||||
|
||||
settings = "os", "arch"
|
||||
|
||||
def build(self):
|
||||
get(self, **self.conan_data["sources"][str(self.version)][str(self.settings.os)][str(self.settings.arch)])
|
||||
|
||||
def package(self):
|
||||
copy(self, "*", src=os.path.join(self.source_folder, "go"), dst=self.package_folder)
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.bindirs = ["bin"]
|
||||
98
recipes/hev-socks5-tunnel/conanfile.py
Normal file
98
recipes/hev-socks5-tunnel/conanfile.py
Normal file
@@ -0,0 +1,98 @@
|
||||
from conan import ConanFile
|
||||
from conan.tools.layout import basic_layout
|
||||
from conan.tools.scm import Git
|
||||
from conan.tools.files import copy, collect_libs
|
||||
from conan.internal.model.pkg_type import PackageType
|
||||
from conan.tools.gnu import AutotoolsToolchain, Autotools
|
||||
from conan.tools.apple import is_apple_os
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
|
||||
required_conan_version = ">=2.26"
|
||||
|
||||
|
||||
class HevSocks5Tunnel(ConanFile):
|
||||
name = "hev-socks5-tunnel"
|
||||
version = "2.14.4"
|
||||
settings = "os", "arch"
|
||||
options = {
|
||||
"shared": [True, False],
|
||||
"as_framework": [True, False],
|
||||
}
|
||||
default_options = {
|
||||
"shared": False,
|
||||
"as_framework": False
|
||||
}
|
||||
|
||||
def config_options(self):
|
||||
if not is_apple_os(self):
|
||||
del self.options.as_framework
|
||||
|
||||
def configure(self):
|
||||
if self.options.get_safe("as_framework"):
|
||||
self.options.shared = False
|
||||
|
||||
def layout(self):
|
||||
basic_layout(self, build_folder=".")
|
||||
|
||||
def source(self):
|
||||
git = Git(self)
|
||||
git.clone(
|
||||
url="https://github.com/heiher/hev-socks5-tunnel.git",
|
||||
target=".",
|
||||
args=["--recurse-submodules", "--branch", self.version]
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
tc = AutotoolsToolchain(self)
|
||||
tc.generate()
|
||||
|
||||
def build(self):
|
||||
autotools = Autotools(self)
|
||||
autotools.make("shared" if self.options.shared else "static")
|
||||
|
||||
if self.options.get_safe("as_framework"):
|
||||
lib_path = os.path.join(self.build_folder, "bin", "libhev-socks5-tunnel.a")
|
||||
self.run(
|
||||
f"libtool -static -o {lib_path}"
|
||||
f" {lib_path}"
|
||||
f" {os.path.join(self.build_folder, "third-part", "lwip", "bin", "liblwip.a")}"
|
||||
f" {os.path.join(self.build_folder, "third-part", "yaml", "bin", "libyaml.a")}"
|
||||
f" {os.path.join(self.build_folder, "third-part", "hev-task-system", "bin", "libhev-task-system.a")}"
|
||||
)
|
||||
|
||||
include_dir = os.path.join(self.build_folder, "framework_include")
|
||||
copy(self, "hev-main.h", src=os.path.join(self.source_folder, "src"), dst=include_dir)
|
||||
copy(self, "module.modulemap", src=os.path.join(self.source_folder), dst=include_dir)
|
||||
|
||||
self.run('xcodebuild -create-xcframework'
|
||||
f' -library {lib_path}'
|
||||
f' -headers {include_dir}'
|
||||
f' -output {os.path.join(self.build_folder, "HevSocks5Tunnel.xcframework")}'
|
||||
)
|
||||
|
||||
def package(self):
|
||||
if self.options.get_safe("as_framework"):
|
||||
shutil.copytree(src=os.path.join(self.build_folder, "HevSocks5Tunnel.xcframework"),
|
||||
dst=os.path.join(self.package_folder, "HevSocks5Tunnel.xcframework"))
|
||||
else:
|
||||
copy(self, "hev-main.h", src=os.path.join(self.source_folder, "src"), dst=os.path.join(self.package_folder, "include"))
|
||||
copy(self, "*.a", src=os.path.join(self.build_folder, "bin"), dst=os.path.join(self.package_folder, "lib"))
|
||||
copy(self, "*.so", src=os.path.join(self.build_folder, "bin"), dst=os.path.join(self.package_folder, "lib"))
|
||||
copy(self, "*.a", src=os.path.join(self.build_folder, "bin", "third-part", "lwip"), dst=os.path.join(self.package_folder, "lib"))
|
||||
copy(self, "*.so", src=os.path.join(self.build_folder, "bin", "third-part", "lwip"), dst=os.path.join(self.package_folder, "lib"))
|
||||
copy(self, "*.a", src=os.path.join(self.build_folder, "bin", "third-part", "yaml"), dst=os.path.join(self.package_folder, "lib"))
|
||||
copy(self, "*.so", src=os.path.join(self.build_folder, "bin", "third-part", "yaml"), dst=os.path.join(self.package_folder, "lib"))
|
||||
copy(self, "*.a", src=os.path.join(self.build_folder, "bin", "third-part", "hev-task-system"), dst=os.path.join(self.package_folder, "lib"))
|
||||
copy(self, "*.so", src=os.path.join(self.build_folder, "bin", "third-part", "hev-task-system"), dst=os.path.join(self.package_folder, "lib"))
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.set_property("cmake_target_name", "heiher::hev-socks5-tunnel")
|
||||
if self.options.get_safe("as_framework"):
|
||||
self.cpp_info.type = PackageType.STATIC
|
||||
self.cpp_info.package_framework = True
|
||||
self.cpp_info.location = os.path.join(self.package_folder, "HevSocks5Tunnel.xcframework")
|
||||
else:
|
||||
self.cpp_info.libraries = collect_libs(self)
|
||||
142
recipes/libssh/conanfile.py
Normal file
142
recipes/libssh/conanfile.py
Normal file
@@ -0,0 +1,142 @@
|
||||
from conan import ConanFile
|
||||
from conan.errors import ConanInvalidConfiguration
|
||||
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps
|
||||
from conan.tools.files import copy, get, rmdir
|
||||
from conan.tools.microsoft import is_msvc_static_runtime, is_msvc
|
||||
from conan.tools.scm import Version
|
||||
import os
|
||||
|
||||
|
||||
required_conan_version = ">=2.21"
|
||||
|
||||
|
||||
class LibSSHRecipe(ConanFile):
|
||||
name = "libssh"
|
||||
version = "0.11.3"
|
||||
user = "amnezia"
|
||||
license = "LGPL-2.1"
|
||||
homepage = "https://www.libssh.org/"
|
||||
description = "multiplatform C library implementing the SSHv2 protocol on client and server side"
|
||||
topics = ("ssh", "shell", "ssh2", "connection")
|
||||
package_type = "library"
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
options = {
|
||||
"shared": [True, False],
|
||||
"fPIC": [True, False],
|
||||
"with_zlib": [True, False],
|
||||
"crypto_backend": ["openssl", "gcrypt", "mbedtls"],
|
||||
"with_symbol_versioning": [True, False],
|
||||
"page_16k": [True, False],
|
||||
}
|
||||
default_options = {
|
||||
"shared": False,
|
||||
"fPIC": True,
|
||||
"with_zlib": True,
|
||||
"crypto_backend": "openssl",
|
||||
"with_symbol_versioning": True,
|
||||
"page_16k": True,
|
||||
}
|
||||
|
||||
def config_options(self):
|
||||
if self.settings.os == "Windows":
|
||||
del self.options.fPIC
|
||||
del self.options.with_symbol_versioning
|
||||
|
||||
def configure(self):
|
||||
if self.options.shared:
|
||||
self.options.rm_safe("fPIC")
|
||||
self.settings.rm_safe("compiler.libcxx")
|
||||
self.settings.rm_safe("compiler.cppstd")
|
||||
|
||||
def layout(self):
|
||||
cmake_layout(self, src_folder="src")
|
||||
|
||||
def requirements(self):
|
||||
if self.options.with_zlib:
|
||||
self.requires("zlib/[>=1.2.11 <2]")
|
||||
if self.options.crypto_backend == "openssl":
|
||||
if self.settings.os == "Android":
|
||||
self.requires("android-openssl/3.5.5")
|
||||
else:
|
||||
self.requires("openssl/[>=1.1 <4]")
|
||||
elif self.options.crypto_backend == "gcrypt":
|
||||
self.requires("libgcrypt/[>=1.8.4 <2]")
|
||||
elif self.options.crypto_backend == "mbedtls":
|
||||
self.requires("mbedtls/3.6.0")
|
||||
|
||||
def validate(self):
|
||||
if self.options.crypto_backend == "mbedtls" and not self.dependencies["mbedtls"].options.enable_threading:
|
||||
raise ConanInvalidConfiguration(f"{self.ref} requires '-o mbedtls/*:enable_threading=True' when using '-o libssh/*:crypto_backend=mbedtls'")
|
||||
|
||||
def source(self):
|
||||
get(self, "https://www.libssh.org/files/0.11/libssh-0.11.3.tar.xz",
|
||||
sha256="7d8a1361bb094ec3f511964e78a5a4dba689b5986e112afabe4f4d0d6c6125c3", strip_root=True
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
tc = CMakeToolchain(self)
|
||||
tc.cache_variables["CLIENT_TESTING"] = False
|
||||
tc.cache_variables["SERVER_TESTING"] = False
|
||||
tc.cache_variables["WITH_EXAMPLES"] = False
|
||||
tc.cache_variables["WITH_GCRYPT"] = self.options.crypto_backend == "gcrypt"
|
||||
tc.cache_variables["WITH_GSSAPI"] = False
|
||||
tc.cache_variables["WITH_MBEDTLS"] = self.options.crypto_backend == "mbedtls"
|
||||
tc.cache_variables["WITH_NACL"] = False
|
||||
tc.cache_variables["WITH_SYMBOL_VERSIONING"] = self.options.get_safe("with_symbol_versioning", True)
|
||||
tc.variables["WITH_ZLIB"] = self.options.with_zlib
|
||||
if is_msvc(self):
|
||||
tc.cache_variables["USE_MSVC_RUNTIME_LIBRARY_DLL"] = not is_msvc_static_runtime(self)
|
||||
tc.cache_variables["CMAKE_POLICY_DEFAULT_CMP0077"] = "NEW"
|
||||
tc.cache_variables["CMAKE_TRY_COMPILE_CONFIGURATION"] = str(self.settings.build_type)
|
||||
if self.settings.os == "Android":
|
||||
if Version(self.settings.get_safe("os.api_level")) < 24:
|
||||
tc.cache_variables["HAVE_IFADDRS_H"] = False
|
||||
tc.cache_variables["HAVE_GLOB_H"] = False
|
||||
tc.preprocessor_definitions["S_IWRITE"] = "S_IRUSR"
|
||||
tc.preprocessor_definitions["S_IWRITE"] = "S_IWUSR"
|
||||
tc.preprocessor_definitions["S_IEXEC"] = "S_IXUSR"
|
||||
if self.options.page_16k:
|
||||
tc.cache_variables["CMAKE_SHARED_LINKER_FLAGS"] = "-Wl,-z,max-page-size=16384"
|
||||
tc.cache_variables["CMAKE_MODULE_LINKER_FLAGS"] = "-Wl,-z,max-page-size=16384"
|
||||
tc.generate()
|
||||
|
||||
deps = CMakeDeps(self)
|
||||
deps.set_property("libgcrypt", "cmake_file_name", "GCrypt")
|
||||
deps.set_property("libgcrypt", "cmake_additional_variables_prefixes", ["GCRYPT"])
|
||||
deps.set_property("libgcrypt", "cmake_extra_variables", {"GCRYPT_FOUND": "TRUE"})
|
||||
deps.set_property("mbedtls", "cmake_additional_variables_prefixes", ["MBEDTLS"])
|
||||
deps.set_property("mbedtls", "cmake_extra_variables", {"MBEDTLS_FOUND": "TRUE"})
|
||||
deps.generate()
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
cmake.build()
|
||||
|
||||
def package(self):
|
||||
copy(self, pattern="COPYING", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder)
|
||||
cmake = CMake(self)
|
||||
cmake.install()
|
||||
rmdir(self, os.path.join(self.package_folder, "lib", "cmake"))
|
||||
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.libs = ["ssh"]
|
||||
if not self.options.shared:
|
||||
self.cpp_info.defines.append("LIBSSH_STATIC=ON")
|
||||
if self.settings.os == "Windows":
|
||||
self.cpp_info.system_libs.extend(["ws2_32", "iphlpapi"])
|
||||
|
||||
self.cpp_info.set_property("cmake_file_name", "libssh")
|
||||
# target and alias names defined at:
|
||||
# ssh https://git.libssh.org/projects/libssh.git/tree/src/CMakeLists.txt?h=libssh-0.10.6#n351
|
||||
# ssh::ssh https://git.libssh.org/projects/libssh.git/tree/src/CMakeLists.txt?h=libssh-0.10.6#n371
|
||||
# ssh-static https://git.libssh.org/projects/libssh.git/tree/src/CMakeLists.txt?h=libssh-0.10.6#n413
|
||||
# ssh::static https://git.libssh.org/projects/libssh.git/tree/src/CMakeLists.txt?h=libssh-0.10.6#n428
|
||||
self.cpp_info.set_property("cmake_target_name", "ssh::ssh")
|
||||
self.cpp_info.set_property(
|
||||
"cmake_target_aliases",
|
||||
["ssh"] if self.options.shared else ["ssh", "ssh-static", "ssh::static"],
|
||||
)
|
||||
# pkg-config defined at https://git.libssh.org/projects/libssh.git/tree/CMakeLists.txt?h=libssh-0.10.6#n124
|
||||
self.cpp_info.set_property("pkg_config_name", "libssh")
|
||||
67
recipes/openvpn-pt-android/conanfile.py
Normal file
67
recipes/openvpn-pt-android/conanfile.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from conan import ConanFile
|
||||
from conan.tools.cmake import cmake_layout, CMake, CMakeToolchain
|
||||
from conan.tools.env import VirtualBuildEnv
|
||||
from conan.tools.files import copy
|
||||
from conan.tools.scm import Git
|
||||
from conan.errors import ConanInvalidConfiguration
|
||||
|
||||
import os
|
||||
|
||||
class OpenvpnPtAndroid(ConanFile):
|
||||
name = "openvpn-pt-android"
|
||||
version = "1.0.0"
|
||||
package_type = "shared-library"
|
||||
settings = "os", "arch", "build_type", "compiler"
|
||||
options = {"page_16k": [True, False]}
|
||||
default_options = {"page_16k": True}
|
||||
|
||||
def layout(self):
|
||||
cmake_layout(self)
|
||||
|
||||
def build_requirements(self):
|
||||
self.tool_requires("swig/4.1.1")
|
||||
self.tool_requires("go/1.26.0")
|
||||
self.tool_requires("cmake/[>=3.4.1 <4]")
|
||||
|
||||
def validate(self):
|
||||
if self.settings.os != "Android":
|
||||
raise ConanInvalidConfiguration(f"{self.name} only supports Android, got {self.settings.os}")
|
||||
|
||||
def source(self):
|
||||
git = Git(self)
|
||||
git.clone(
|
||||
url="https://github.com/amnezia-vpn/openvpn-pt-android.git",
|
||||
target=".",
|
||||
args=["--recurse-submodules", "--branch", "update-ovpn3"]
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
tc = CMakeToolchain(self)
|
||||
tc.variables["ANDROID_PACKAGE_NAME"] = "org.amnezia.vpn"
|
||||
tc.variables["ANDROID_PLATFORM"] = 24
|
||||
if self.options.page_16k:
|
||||
page_flag = "-Wl,-z,max-page-size=16384"
|
||||
tc.cache_variables["CMAKE_SHARED_LINKER_FLAGS"] = page_flag
|
||||
tc.cache_variables["CMAKE_EXE_LINKER_FLAGS"] = page_flag
|
||||
tc.generate()
|
||||
|
||||
vbe = VirtualBuildEnv(self)
|
||||
if self.options.page_16k:
|
||||
vbe.environment().define("CGO_LDFLAGS", "-Wl,-z,max-page-size=16384")
|
||||
vbe.generate()
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
cmake.build(target=["ck_ovpn_plugin_go", "ovpn3", "ovpnutil", "rsapss"])
|
||||
|
||||
def package(self):
|
||||
copy(self, "*.h", src=self.build_folder, dst=os.path.join(self.package_folder, "include"))
|
||||
copy(self, "*.so", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"))
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.set_property("cmake_target_name", "amnezia::openvpn-pt-android")
|
||||
self.cpp_info.libs = ["ovpn3", "ovpnutil", "rsapss"]
|
||||
self.cpp_info.set_property("cmake_extra_variables", {
|
||||
"OPENVPN_PT_ANDROID_LIBCK_OVPN_PLUGIN_PATH": os.path.join(self.package_folder, "lib", "libck-ovpn-plugin.so"),
|
||||
})
|
||||
48
recipes/openvpn/conanfile.py
Normal file
48
recipes/openvpn/conanfile.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from conan import ConanFile
|
||||
from conan.tools.files import get, copy
|
||||
from conan.tools.gnu import Autotools, AutotoolsToolchain, AutotoolsDeps
|
||||
from conan.tools.layout import basic_layout
|
||||
|
||||
import os
|
||||
|
||||
class Openvpn(ConanFile):
|
||||
name = "openvpn"
|
||||
version = "2.7.0"
|
||||
package_type = "application"
|
||||
settings = "os", "build_type", "arch"
|
||||
|
||||
def layout(self):
|
||||
basic_layout(self)
|
||||
|
||||
def build_requirements(self):
|
||||
self.tool_requires("libtool/2.4.7")
|
||||
self.tool_requires("automake/1.16.5")
|
||||
|
||||
def requirements(self):
|
||||
self.requires("openssl/[>=1.1.0]", visible=False)
|
||||
self.requires("lz4/[>=1.7.1]", visible=False)
|
||||
self.requires("lzo/2.10", visible=False)
|
||||
|
||||
def source(self):
|
||||
get(self, f"https://github.com/OpenVPN/openvpn/archive/refs/tags/v{self.version}.zip",
|
||||
sha256="1a65d8587f932c13d55b1f175ff2e1d61d795d9092788662e888054854d4ee3d", strip_root=True
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
tc = AutotoolsToolchain(self)
|
||||
tc.generate()
|
||||
deps = AutotoolsDeps(self)
|
||||
deps.generate()
|
||||
|
||||
def build(self):
|
||||
at = Autotools(self)
|
||||
at.autoreconf()
|
||||
at.configure()
|
||||
at.make()
|
||||
|
||||
def package(self):
|
||||
copy(self, "openvpn", src=os.path.join(self.build_folder, "src", "openvpn"), dst=self.package_folder)
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.exe = True
|
||||
self.cpp_info.location = os.path.join(self.package_folder, "openvpn")
|
||||
72
recipes/openvpnadapter/conanfile.py
Normal file
72
recipes/openvpnadapter/conanfile.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from conan import ConanFile
|
||||
from conan.tools.layout import basic_layout
|
||||
from conan.tools.apple import is_apple_os
|
||||
from conan.errors import ConanInvalidConfiguration
|
||||
from conan.tools.scm import Git
|
||||
from conan.internal.model.pkg_type import PackageType
|
||||
from conan.tools.files import chdir
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
class OpenVPNAdapter(ConanFile):
|
||||
name = "openvpnadapter"
|
||||
version = "1.0.0"
|
||||
settings = "os", "build_type"
|
||||
|
||||
@property
|
||||
def _sdk(self):
|
||||
return str(self.settings.get_safe("os.sdk", "macosx"))
|
||||
|
||||
@property
|
||||
def _platform(self):
|
||||
return {
|
||||
"macosx": "macOS",
|
||||
"iphoneos": "iOS",
|
||||
"iphonesimulator": "iOS Simulator"
|
||||
}.get(self._sdk)
|
||||
|
||||
@property
|
||||
def _configuration(self):
|
||||
return "Debug" if self.settings.get_safe("build_type") == "Debug" else "Release"
|
||||
|
||||
def layout(self):
|
||||
basic_layout(self)
|
||||
|
||||
def validate(self):
|
||||
if not is_apple_os(self):
|
||||
raise ConanInvalidConfiguration(
|
||||
f"There is absolutely no point building Apple framework for {self.settings.os}"
|
||||
)
|
||||
|
||||
def source(self):
|
||||
git = Git(self)
|
||||
git.clone(
|
||||
url="https://github.com/amnezia-vpn/OpenVPNAdapter.git",
|
||||
target=".",
|
||||
args=["--recurse-submodules", "--branch", "master-amnezia"]
|
||||
)
|
||||
|
||||
def build(self):
|
||||
with chdir(self, self.source_folder):
|
||||
self.run("xcrun xcodebuild"
|
||||
" -project OpenVPNAdapter.xcodeproj"
|
||||
" -scheme OpenVPNAdapter"
|
||||
" -configuration Release"
|
||||
f" -destination 'generic/platform={self._platform}'"
|
||||
f" -sdk {self._sdk}"
|
||||
f' "CONFIGURATION_BUILD_DIR={self.build_folder}"'
|
||||
f' "BUILT_PRODUCTS_DIR={self.build_folder}"'
|
||||
" BUILD_LIBRARY_FOR_DISTRIBUTION=YES"
|
||||
" CODE_SIGNING_ALLOWED=NO"
|
||||
)
|
||||
|
||||
def package(self):
|
||||
shutil.copytree(os.path.join(self.build_folder, "OpenVPNAdapter.framework"),
|
||||
os.path.join(self.package_folder, "OpenVPNAdapter.framework"))
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.set_property("cmake_target_name", "amnezia::openvpnadapter")
|
||||
self.cpp_info.type = PackageType.STATIC
|
||||
self.cpp_info.package_framework = True
|
||||
self.cpp_info.location = os.path.join(self.package_folder, "OpenVPNAdapter.framework")
|
||||
80
recipes/tun2socks/conanfile.py
Normal file
80
recipes/tun2socks/conanfile.py
Normal file
@@ -0,0 +1,80 @@
|
||||
from conan import ConanFile
|
||||
from conan.tools.layout import basic_layout
|
||||
from conan.tools.files import get, copy, chdir
|
||||
from conan.errors import ConanInvalidConfiguration
|
||||
from conan.tools.gnu import Autotools, AutotoolsToolchain
|
||||
from conan.tools.env import Environment
|
||||
|
||||
import os
|
||||
|
||||
class Tun2Socks(ConanFile):
|
||||
name = "tun2socks"
|
||||
version = "2.6.0"
|
||||
package_type = "application"
|
||||
settings = "os", "arch"
|
||||
|
||||
@property
|
||||
def _goos(self):
|
||||
return {
|
||||
"Linux": "linux",
|
||||
"Macos": "darwin",
|
||||
"Windows": "windows"
|
||||
}.get(str(self.settings.os))
|
||||
|
||||
@property
|
||||
def _goarch(self):
|
||||
return {
|
||||
"x86": "386",
|
||||
"x86_64": "amd64",
|
||||
"armv8": "arm64"
|
||||
}.get(str(self.settings.arch))
|
||||
|
||||
@property
|
||||
def _is_windows(self):
|
||||
return str(self.settings.get_safe("os")).startswith("Windows")
|
||||
|
||||
@property
|
||||
def _ext(self):
|
||||
return ".exe" if self._is_windows else ""
|
||||
|
||||
def layout(self):
|
||||
basic_layout(self)
|
||||
|
||||
def validate(self):
|
||||
if not self._goos or not self._goarch:
|
||||
raise ConanInvalidConfiguration(
|
||||
f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}"
|
||||
)
|
||||
|
||||
def build_requirements(self):
|
||||
self.tool_requires("go/1.26.0")
|
||||
|
||||
def source(self):
|
||||
get(self, f"https://github.com/xjasonlyu/tun2socks/archive/refs/tags/v{self.version}.zip",
|
||||
sha256="a7ef9cec1c30dfe9971af89a8aac767fd3d2a4df833e92b635642c2f0204c701", strip_root=True
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
tc = AutotoolsToolchain(self)
|
||||
env = Environment()
|
||||
env.define("CGO_LDFLAGS", tc.ldflags)
|
||||
env.define("CGO_CFLAGS", tc.cflags)
|
||||
env.define("GOOS", self._goos)
|
||||
env.define("GOARCH", self._goarch)
|
||||
tc.generate(env)
|
||||
|
||||
def build(self):
|
||||
with chdir(self, self.source_folder):
|
||||
at = Autotools(self)
|
||||
at.make("tun2socks")
|
||||
|
||||
def package(self):
|
||||
copy(self, "tun2socks", src=self.build_folder, dst=self.package_folder)
|
||||
if self._is_windows:
|
||||
with chdir(self, self.package_folder):
|
||||
os.rename(src="tun2socks", dst="tun2socks.exe")
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.exe = True
|
||||
self.cpp_info.location = os.path.join(self.package_folder, f"tun2socks{self._ext}")
|
||||
self.cpp_info.set_property("cmake_target_name", "xjasonlyu::tun2socks")
|
||||
29
recipes/v2ray-rules-dat/conanfile.py
Normal file
29
recipes/v2ray-rules-dat/conanfile.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from conan import ConanFile
|
||||
from conan.tools.layout import basic_layout
|
||||
from conan.tools.files import download, copy
|
||||
|
||||
import os
|
||||
|
||||
class V2rayRulesDat(ConanFile):
|
||||
name = "v2ray-rules-dat"
|
||||
version = "202603162227"
|
||||
|
||||
def layout(self):
|
||||
basic_layout(self, build_folder=".")
|
||||
|
||||
def source(self):
|
||||
# TODO(ygurov): build from source instead of plain copying
|
||||
download(self, filename="geoip.dat", url=f"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/download/{self.version}/geoip.dat",
|
||||
sha256="e48b925d985d7bf33cfee76f309241af0f1779699963b69363dec2c4740041d1")
|
||||
download(self, filename="geosite.dat", url=f"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/download/{self.version}/geosite.dat",
|
||||
sha256="a2f83e25b8be3f089cfdd9423fc7b6eda5a0d4060919917902711d65acac1e0c")
|
||||
|
||||
def package(self):
|
||||
copy(self, "*.dat", src=self.build_folder, dst=self.package_folder)
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.set_property("cmake_target_name", "Loyalsoldier::v2ray-rules-dat")
|
||||
self.cpp_info.set_property("cmake_extra_variables", {
|
||||
"GEOSITE_DAT_PATH": os.path.join(self.package_folder, "geosite.dat"),
|
||||
"GEOIP_DAT_PATH": os.path.join(self.package_folder, "geoip.dat")
|
||||
})
|
||||
5
recipes/wintun/conanfile.py
Normal file
5
recipes/wintun/conanfile.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from conan import ConanFile
|
||||
|
||||
class PackageConan(ConanFile):
|
||||
name = "wintun"
|
||||
version = "1.0.0"
|
||||
@@ -6,13 +6,6 @@ project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION})
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if(LINUX)
|
||||
set(CMAKE_BUILD_RPATH "\$ORIGIN/../lib")
|
||||
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib")
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
endif()
|
||||
|
||||
if(NOT IOS AND NOT ANDROID AND NOT MACOS_NE)
|
||||
add_subdirectory(server)
|
||||
endif()
|
||||
|
||||
@@ -9,62 +9,11 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
find_package(Qt6 REQUIRED COMPONENTS DBus Core Network Widgets RemoteObjects Core5Compat Concurrent)
|
||||
qt_standard_project_setup()
|
||||
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
|
||||
|
||||
set(AMNEZIA_XRAY_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../../client/3rd-prebuilt/3rd-prebuilt/amnezia_xray")
|
||||
if(WIN32)
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
set(AMNEZIA_XRAY_LIB_PATH "${AMNEZIA_XRAY_ROOT_DIR}/windows/x86_64/amnezia_xray.lib")
|
||||
set(AMNEZIA_XRAY_INCLUDE_DIR "${AMNEZIA_XRAY_ROOT_DIR}/windows/x86_64")
|
||||
else()
|
||||
set(AMNEZIA_XRAY_LIB_PATH "${AMNEZIA_XRAY_ROOT_DIR}/windows/x86/amnezia_xray.lib")
|
||||
set(AMNEZIA_XRAY_INCLUDE_DIR "${AMNEZIA_XRAY_ROOT_DIR}/windows/x86")
|
||||
endif()
|
||||
elseif(APPLE AND NOT IOS)
|
||||
set(AMNEZIA_XRAY_LIB_PATH "${AMNEZIA_XRAY_ROOT_DIR}/macos/x86_64/amnezia_xray.a")
|
||||
set(AMNEZIA_XRAY_INCLUDE_DIR "${AMNEZIA_XRAY_ROOT_DIR}/macos/x86_64")
|
||||
elseif(LINUX)
|
||||
set(AMNEZIA_XRAY_LIB_PATH "${AMNEZIA_XRAY_ROOT_DIR}/linux/x86_64/amnezia_xray.a")
|
||||
set(AMNEZIA_XRAY_INCLUDE_DIR "${AMNEZIA_XRAY_ROOT_DIR}/linux/x86_64")
|
||||
endif()
|
||||
|
||||
set(QSIMPLECRYPTO_DIR ${CMAKE_CURRENT_LIST_DIR}/../../client/3rd/QSimpleCrypto/src)
|
||||
|
||||
|
||||
set(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../../client/3rd-prebuilt/3rd-prebuilt/openssl/")
|
||||
set(OPENSSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/lib")
|
||||
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/windows/include")
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/windows/win64/libssl.lib")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win64/libcrypto.lib")
|
||||
else()
|
||||
set(OPENSSL_LIB_SSL_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libssl.lib")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libcrypto.lib")
|
||||
endif()
|
||||
|
||||
|
||||
if(WIN32)
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/windows/include")
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win64/libcrypto.lib")
|
||||
else()
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/windows/win32/libcrypto.lib")
|
||||
endif()
|
||||
elseif(APPLE AND NOT IOS)
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/macos/include")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/macos/lib/libcrypto.a")
|
||||
elseif(LINUX)
|
||||
set(OPENSSL_INCLUDE_DIR "${OPENSSL_ROOT_DIR}/linux/include")
|
||||
set(OPENSSL_LIB_CRYPTO_PATH "${OPENSSL_ROOT_DIR}/linux/x86_64/libcrypto.a")
|
||||
endif()
|
||||
|
||||
set(OPENSSL_USE_STATIC_LIBS TRUE)
|
||||
|
||||
include_directories(
|
||||
${AMNEZIA_XRAY_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${QSIMPLECRYPTO_DIR}
|
||||
)
|
||||
|
||||
@@ -75,7 +24,6 @@ set(HEADERS
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipctun2socksprocess.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/localserver.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../common/logger/logger.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/router.h
|
||||
@@ -97,7 +45,6 @@ set(SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/core/networkUtilities.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipctun2socksprocess.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/localserver.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../common/logger/logger.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/main.cpp
|
||||
@@ -242,8 +189,6 @@ if(WIN32)
|
||||
gdi32
|
||||
Advapi32
|
||||
Kernel32
|
||||
${AMNEZIA_XRAY_LIB_PATH}
|
||||
${OPENSSL_LIB_CRYPTO_PATH}
|
||||
qt6keychain
|
||||
)
|
||||
|
||||
@@ -292,8 +237,6 @@ if(APPLE)
|
||||
|
||||
set(LIBS
|
||||
resolv
|
||||
${AMNEZIA_XRAY_LIB_PATH}
|
||||
${OPENSSL_LIB_CRYPTO_PATH}
|
||||
qt6keychain
|
||||
)
|
||||
|
||||
@@ -331,7 +274,6 @@ if(LINUX)
|
||||
)
|
||||
|
||||
set(LIBS
|
||||
${AMNEZIA_XRAY_LIB_PATH}
|
||||
${OPENSSL_LIB_CRYPTO_PATH}
|
||||
qt6keychain
|
||||
-static-libstdc++
|
||||
@@ -353,19 +295,15 @@ include_directories(
|
||||
|
||||
|
||||
add_executable(${PROJECT} ${SOURCES} ${HEADERS} ${RESOURCES})
|
||||
|
||||
if(LINUX)
|
||||
target_link_options(${PROJECT} PRIVATE "LINKER:--disable-new-dtags")
|
||||
set_target_properties(${PROJECT} PROPERTIES
|
||||
BUILD_RPATH "\$ORIGIN/../lib"
|
||||
INSTALL_RPATH "\$ORIGIN/../lib"
|
||||
INSTALL_RPATH_USE_LINK_PATH FALSE
|
||||
)
|
||||
set_property(TARGET ${PROJECT} PROPERTY BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT} PRIVATE Qt6::Core Qt6::Widgets Qt6::Network Qt6::RemoteObjects Qt6::Core5Compat Qt6::DBus Qt6::Concurrent ${LIBS})
|
||||
target_compile_definitions(${PROJECT} PRIVATE "MZ_$<UPPER_CASE:${MZ_PLATFORM_NAME}>")
|
||||
|
||||
find_package(amnezia-xray-bindings REQUIRED)
|
||||
target_link_libraries(${PROJECT} PRIVATE amnezia::xray-bindings)
|
||||
|
||||
find_package(openssl REQUIRED)
|
||||
target_link_libraries(${PROJECT} PRIVATE OpenSSL::SSL OpenSSL::Crypto)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_compile_definitions(${PROJECT} PRIVATE "MZ_DEBUG")
|
||||
endif()
|
||||
@@ -399,7 +337,6 @@ endif()
|
||||
|
||||
qt_add_repc_sources(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc_interface.rep)
|
||||
qt_add_repc_sources(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc_process_interface.rep)
|
||||
qt_add_repc_sources(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipc_process_tun2socks.rep)
|
||||
|
||||
# copy deploy artifacts required to run the application to the debug build folder
|
||||
if(WIN32)
|
||||
@@ -421,10 +358,38 @@ add_custom_command(
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
COMMAND_EXPAND_LISTS
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:Debug>,copy_directory,true>
|
||||
${CMAKE_SOURCE_DIR}/client/3rd-prebuilt/deploy-prebuilt/${DEPLOY_PLATFORM_PATH}
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
COMMAND_EXPAND_LISTS
|
||||
|
||||
if(NOT WIN32)
|
||||
find_package(awg-go REQUIRED)
|
||||
add_custom_command(TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
$<TARGET_FILE:amnezia::awg-go>
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
)
|
||||
endif()
|
||||
|
||||
find_package(openvpn REQUIRED)
|
||||
add_custom_command(TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
$<TARGET_FILE:openvpn::openvpn>
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
)
|
||||
|
||||
find_package(tun2socks REQUIRED)
|
||||
add_custom_command(TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
$<TARGET_FILE:xjasonlyu::tun2socks>
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
)
|
||||
|
||||
find_package(v2ray-rules-dat REQUIRED)
|
||||
add_custom_command(TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${GEOSITE_DAT_PATH}
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
)
|
||||
add_custom_command(TARGET ${PROJECT} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${GEOIP_DAT_PATH}
|
||||
$<TARGET_FILE_DIR:${PROJECT}>
|
||||
)
|
||||
|
||||
@@ -33,18 +33,10 @@ KillSwitch* KillSwitch::instance()
|
||||
|
||||
bool KillSwitch::init()
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
if (!LinuxFirewall::isInstalled()) {
|
||||
LinuxFirewall::install();
|
||||
}
|
||||
m_appSettigns = QSharedPointer<SecureQSettings>(new SecureQSettings(ORGANIZATION_NAME, APPLICATION_NAME, nullptr));
|
||||
#endif
|
||||
#ifdef Q_OS_MACOS
|
||||
if (!MacOSFirewall::isInstalled()) {
|
||||
MacOSFirewall::install();
|
||||
}
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||
m_appSettigns = QSharedPointer<SecureQSettings>(new SecureQSettings(ORGANIZATION_NAME, APPLICATION_NAME, nullptr));
|
||||
#endif
|
||||
|
||||
if (isStrictKillSwitchEnabled()) {
|
||||
return disableAllTraffic();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ LocalServer::LocalServer(QObject *parent) : QObject(parent),
|
||||
if (!m_isRemotingEnabled) {
|
||||
m_isRemotingEnabled = true;
|
||||
m_serverNode.enableRemoting(&m_ipcServer);
|
||||
m_serverNode.enableRemoting(&m_tun2socks);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -51,8 +50,8 @@ LocalServer::LocalServer(QObject *parent) : QObject(parent),
|
||||
}
|
||||
|
||||
m_networkWatcher.initialize();
|
||||
connect(&m_networkWatcher, &NetworkWatcher::sleepMode, &m_ipcServer, &IpcServer::networkChange);
|
||||
connect(&m_networkWatcher, &NetworkWatcher::networkChange, &m_ipcServer, &IpcServer::networkChange);
|
||||
connect(&m_networkWatcher, &NetworkWatcher::networkChanged, &m_ipcServer, &IpcServer::networkChanged);
|
||||
connect(&m_networkWatcher, &NetworkWatcher::wakeup, &m_ipcServer, &IpcServer::wakeup);
|
||||
KillSwitch::instance()->init();
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
|
||||
@@ -38,7 +38,6 @@ public:
|
||||
~LocalServer();
|
||||
QSharedPointer<QLocalServer> m_server;
|
||||
IpcServer m_ipcServer;
|
||||
IpcProcessTun2Socks m_tun2socks;
|
||||
QRemoteObjectHost m_serverNode;
|
||||
bool m_isRemotingEnabled = false;
|
||||
|
||||
|
||||
@@ -318,6 +318,40 @@ bool RouterWin::createTun(const QString &dev, const QString &subnet)
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE hEvent = CreateEvent(nullptr, true, false, nullptr);
|
||||
if (!hEvent) {
|
||||
qCritical() << "Failed to allocate event object";
|
||||
return false;
|
||||
}
|
||||
auto _guardEvent = qScopeGuard([hEvent](){ CloseHandle(hEvent); });
|
||||
|
||||
struct {
|
||||
HANDLE hEvent;
|
||||
NET_LUID luid;
|
||||
const QString &subnet;
|
||||
bool found;
|
||||
} ctx = { .hEvent = hEvent, .luid = luid, .subnet = subnet, .found = false };
|
||||
|
||||
auto cb = [](void *priv, MIB_UNICASTIPADDRESS_ROW *row, MIB_NOTIFICATION_TYPE NotificationType) {
|
||||
auto* c = reinterpret_cast<decltype(ctx)*>(priv);
|
||||
if (row != nullptr && row->InterfaceLuid.Value == c->luid.Value && row->Address.si_family == AF_INET) {
|
||||
char ip[INET_ADDRSTRLEN];
|
||||
inet_ntop(row->Address.Ipv4.sin_family, &row->Address.Ipv4.sin_addr, ip, INET_ADDRSTRLEN);
|
||||
if (c->subnet == ip) {
|
||||
c->found = true;
|
||||
SetEvent(c->hEvent);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
HANDLE hNotif;
|
||||
res = NotifyUnicastIpAddressChange(AF_INET, cb, &ctx, false, &hNotif);
|
||||
if (res != NO_ERROR) {
|
||||
qCritical() << "Failed to subscribe to interface change";
|
||||
return false;
|
||||
}
|
||||
auto _guardNotif = qScopeGuard([hNotif](){ CancelMibChangeNotify2(hNotif); });
|
||||
|
||||
MIB_UNICASTIPADDRESS_ROW row;
|
||||
InitializeUnicastIpAddressEntry(&row);
|
||||
|
||||
@@ -337,7 +371,13 @@ bool RouterWin::createTun(const QString &dev, const QString &subnet)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
res = WaitForSingleObject(hEvent, 10000);
|
||||
if (res == WAIT_TIMEOUT) {
|
||||
qCritical() << "Timeout of waiting for IP assignment for " << dev << " device";
|
||||
return false;
|
||||
}
|
||||
|
||||
return ctx.found;
|
||||
}
|
||||
|
||||
void RouterWin::suspendWcmSvc(bool suspend)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
void Xray::startXray(const QString &cfg)
|
||||
bool Xray::startXray(const QString &cfg)
|
||||
{
|
||||
qDebug() << "Xray::startXray()";
|
||||
|
||||
@@ -40,34 +40,38 @@ void Xray::startXray(const QString &cfg)
|
||||
|
||||
if (auto err = amnezia_xray_setsockcallback(ctxSockCallback, this); err != nullptr) {
|
||||
qDebug() << "[xray] sockopt failed: " << err;
|
||||
free(err);
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray bytes = cfg.toUtf8();
|
||||
if (auto err = amnezia_xray_configure(bytes.data()); err != nullptr) {
|
||||
qDebug() << "[xray] configuration failed: " << err;
|
||||
free(err);
|
||||
return;
|
||||
amnezia_xray_free(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
amnezia_xray_setloghandler(ctxLogHandler, this);
|
||||
|
||||
QByteArray bytes = cfg.toUtf8();
|
||||
if (auto err = amnezia_xray_configure(bytes.data()); err != nullptr) {
|
||||
qDebug() << "[xray] configuration failed: " << err;
|
||||
amnezia_xray_free(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto err = amnezia_xray_start(); err != nullptr) {
|
||||
qDebug() << "[xray] failed to start: " << err;
|
||||
free(err);
|
||||
return;
|
||||
amnezia_xray_free(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Xray::stopXray()
|
||||
bool Xray::stopXray()
|
||||
{
|
||||
qDebug() << "Xray::stopXray()";
|
||||
if (auto err = amnezia_xray_stop(); err != nullptr) {
|
||||
qDebug() << "[xray] failed to stop: " << err;
|
||||
free(err);
|
||||
return;
|
||||
amnezia_xray_free(err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Xray::logHandler(char* str)
|
||||
|
||||
@@ -12,8 +12,8 @@ public:
|
||||
return instance;
|
||||
}
|
||||
|
||||
void startXray(const QString& cfg);
|
||||
void stopXray();
|
||||
bool startXray(const QString& cfg);
|
||||
bool stopXray();
|
||||
|
||||
private:
|
||||
static void ctxSockCallback(uintptr_t fd, void* ctx) {
|
||||
|
||||
Reference in New Issue
Block a user