diff --git a/CMakeLists.txt b/CMakeLists.txt index 31892312f..1591f0b0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4094,6 +4094,7 @@ if (GUI) MACOSX_BUNDLE_BUNDLE_NAME ${PACKAGE_NAME} MACOSX_BUNDLE_INFO_PLIST ${APP_MACOSX_BUNDLE_INFO} XCODE_GENERATE_SCHEME "TRUE" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "it.gui.ios.yass" XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon" XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" @@ -4108,7 +4109,7 @@ if (GUI) set_target_properties(${APP_NAME} PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${XCODE_CODESIGN_IDENTITY}" XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${XCODE_DEPLOYMENT_TEAM}" - XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Auto") + XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Automatic") endif() # Workaround for https://gitlab.kitware.com/cmake/cmake/-/issues/15183 # Apps must have install step enabled @@ -4116,6 +4117,58 @@ if (GUI) XCODE_ATTRIBUTE_SKIP_INSTALL NO XCODE_ATTRIBUTE_INSTALL_PATH "$(LOCAL_APPS_DIR)" ) + + # ======================= + # PacketTunnel extensions + # ======================= + find_library(NetworkExtension_LIBRARY NetworkExtension REQUIRED) + + set(PLUGIN_SRC + src/ios/tun2proxy.h + src/ios/tun2proxy.mm + src/ios/extensions/PacketTunnelProvider.h + src/ios/extensions/PacketTunnelProvider.mm + src/ios/extensions/PacketTunnel.entitlements + ) + + add_executable(PacketTunnel MACOSX_BUNDLE ${PLUGIN_SRC}) + + target_include_directories(PacketTunnel PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/src/ios/extensions) + target_compile_options(PacketTunnel PRIVATE -fapplication-extension -fmodules -gmodules -fobjc-arc -fobjc-weak) + target_link_libraries(PacketTunnel PRIVATE ${NetworkExtension_LIBRARY}) + set_target_properties(PacketTunnel PROPERTIES LINK_OPTIONS -fapplication-extension -e _NSExtensionMain -fobjc-arc -fobjc-link-runtime) + + set_target_properties(PacketTunnel PROPERTIES + OUTPUT_NAME "PacketTunnel" + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/src/ios/extensions/Info.plist + XCODE_PRODUCT_TYPE com.apple.product-type.app-extension + XCODE_GENERATE_SCHEME "TRUE" + MACOSX_BUNDLE_GUI_IDENTIFIER "it.gui.ios.yass.PacketTunnel" + XCODE_ATTRIBUTE_PRODUCT_NAME "PacketTunnel" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "it.gui.ios.yass.PacketTunnel" + XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path" + XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES" + XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11" + XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "" + ) + + if ((NOT XCODE_CODESIGN_IDENTITY STREQUAL "-") OR XCODE_DEPLOYMENT_TEAM) + set_target_properties(PacketTunnel PROPERTIES + XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_CURRENT_SOURCE_DIR}/src/ios/extensions/PacketTunnel.entitlements + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${XCODE_CODESIGN_IDENTITY}" + XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${XCODE_DEPLOYMENT_TEAM}" + XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Automatic") + endif() + + # Workaround for https://gitlab.kitware.com/cmake/cmake/-/issues/15183 + # Apps must have install step enabled + set_target_properties(PacketTunnel PROPERTIES + XCODE_ATTRIBUTE_SKIP_INSTALL NO + XCODE_ATTRIBUTE_INSTALL_PATH "$(LOCAL_APPS_DIR)" + ) endif() if (NOT CMAKE_SKIP_INSTALL_RULES) @@ -4210,7 +4263,7 @@ if (BUILD_TESTS) set_target_properties(yass_test PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${XCODE_CODESIGN_IDENTITY}" XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${XCODE_DEPLOYMENT_TEAM}" - XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Auto") + XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Automatic") endif() else() add_executable(yass_test ${yass_test_SOURCE}) @@ -4328,7 +4381,7 @@ if (BUILD_BENCHMARKS) set_target_properties(yass_benchmark PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${XCODE_CODESIGN_IDENTITY}" XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${XCODE_DEPLOYMENT_TEAM}" - XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Auto") + XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Automatic") endif() else() add_executable(yass_benchmark diff --git a/src/ios/extensions/Info.plist b/src/ios/extensions/Info.plist new file mode 100644 index 000000000..c66ded50b --- /dev/null +++ b/src/ios/extensions/Info.plist @@ -0,0 +1,13 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.networkextension.packet-tunnel + NSExtensionPrincipalClass + PacketTunnelProvider + + + diff --git a/src/ios/extensions/PacketTunnel.entitlements b/src/ios/extensions/PacketTunnel.entitlements new file mode 100644 index 000000000..7810b4b19 --- /dev/null +++ b/src/ios/extensions/PacketTunnel.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.it.gui.ios.yass + + + diff --git a/src/ios/extensions/PacketTunnelProvider.h b/src/ios/extensions/PacketTunnelProvider.h new file mode 100644 index 000000000..b99a63c1d --- /dev/null +++ b/src/ios/extensions/PacketTunnelProvider.h @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Chilledheart */ + +#import + +@interface PacketTunnelProvider : NEPacketTunnelProvider + +@end diff --git a/src/ios/extensions/PacketTunnelProvider.mm b/src/ios/extensions/PacketTunnelProvider.mm new file mode 100644 index 000000000..6d1274891 --- /dev/null +++ b/src/ios/extensions/PacketTunnelProvider.mm @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Chilledheart */ + +#import "PacketTunnelProvider.h" + +@implementation PacketTunnelProvider + +- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(NSError *))completionHandler { + // Add code here to start the process of connecting the tunnel. +} + +- (void)stopTunnelWithReason:(NEProviderStopReason)reason completionHandler:(void (^)(void))completionHandler { + // Add code here to start the process of stopping the tunnel. + completionHandler(); +} + +- (void)handleAppMessage:(NSData *)messageData completionHandler:(void (^)(NSData *))completionHandler { + // Add code here to handle the message. +} + +- (void)sleepWithCompletionHandler:(void (^)(void))completionHandler { + // Add code here to get ready to sleep. + completionHandler(); +} + +- (void)wake { + // Add code here to wake up. +} + +@end diff --git a/src/ios/tun2proxy.h b/src/ios/tun2proxy.h new file mode 100644 index 000000000..8df38b02c --- /dev/null +++ b/src/ios/tun2proxy.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Chilledheart */ +#ifndef YASS_IOS_TUN2PROXY +#define YASS_IOS_TUN2PROXY + +#import + +@class NEPacketTunnelFlow; +@class NEPacket; + +void Tun2Proxy_Init(NEPacketTunnelFlow *flow); +void Tun2Proxy_ForwardReadPackets(NSArray *packets); +void Tun2Proxy_Destroy(); + +#endif // YASS_IOS_TUN2PROXY diff --git a/src/ios/tun2proxy.mm b/src/ios/tun2proxy.mm new file mode 100644 index 000000000..8f7e99500 --- /dev/null +++ b/src/ios/tun2proxy.mm @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Chilledheart */ +#include "ios/tun2proxy.h" + +#import + +struct InitContent { + __weak NEPacketTunnelFlow *packetFlow; +}; + +struct ReadPacketContent { + NSArray *packets; +}; + +static size_t GetPacketCount(void *content, void* packets) { + NSArray *array = reinterpret_cast(packets)->packets; + return [array count]; +} + +static const void* GetPacketDataAtIndex(void *content, void* packets, int index) { + NSArray *array = reinterpret_cast(packets)->packets; + NEPacket *packet = array[index]; + uint32_t prefix = CFSwapInt32HostToBig((uint32_t)packet.protocolFamily); + // Prepend data with network protocol. It should be done because on tun2proxy + // uses uint32_t prefixes containing network protocol. + NSMutableData *data = [[NSMutableData alloc] initWithCapacity:sizeof(prefix) + packet.data.length]; + [data appendBytes:&prefix length:sizeof(prefix)]; + [data appendData:packet.data]; + + return data.bytes; +} + +static size_t GetPacketSizeAtIndex(void *content, void* packets, int index) { + NSArray *array = reinterpret_cast(packets)->packets; + return sizeof(uint32_t) + [[array[index] data] length]; +} + +static NEPacket *packetFromData(NSData *data) { + // Get network protocol from prefix + NSUInteger prefixSize = sizeof(uint32_t); + + if (data.length < prefixSize) { + return nil; + } + + uint32_t protocol = PF_UNSPEC; + [data getBytes:&protocol length:prefixSize]; + protocol = CFSwapInt32BigToHost(protocol); + + NSRange range = NSMakeRange(prefixSize, data.length - prefixSize); + NSData *packetData = [data subdataWithRange:range]; + + return [[NEPacket alloc] initWithData:packetData protocolFamily:protocol]; +} + +static void WritePackets(void* content, void** packets, size_t* packetLengths, + int packetsCount) { + InitContent *c = reinterpret_cast(content); + NEPacketTunnelFlow* packetFlow = c->packetFlow;; + NSMutableArray *packetsArray = [NSMutableArray array]; + for (int i = 0; i < packetsCount; ++i) { + NSData *data = [NSData dataWithBytes:packets[i] length:packetLengths[i]]; + NEPacket *packet = packetFromData(data); + [packetsArray addObject:packet]; + } + [packetFlow writePacketObjects:packetsArray]; +} + +extern "C" +void tun2proxy_init(void* content, decltype(WritePackets)); + +extern "C" +void tun2proxy_read_packets(void* packets, decltype(GetPacketCount), + decltype(GetPacketDataAtIndex), + decltype(GetPacketSizeAtIndex)); + +extern "C" +void* tun2proxy_destroy(); + +void Tun2Proxy_Init(NEPacketTunnelFlow *packetFlow) { + InitContent *c = new InitContent; + c->packetFlow = packetFlow; + tun2proxy_init(c, WritePackets); +} + +void Tun2Proxy_ForwardReadPackets(NSArray *packets) { + ReadPacketContent p; + p.packets = packets; + tun2proxy_read_packets(&p, GetPacketCount, GetPacketDataAtIndex, + GetPacketSizeAtIndex); +} + +void Tun2Proxy_Destroy() { + InitContent *c = reinterpret_cast(tun2proxy_destroy()); + delete c; +}