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;
+}