From 029570e5ae03d0d4df5dffe2d7a483e786de1d01 Mon Sep 17 00:00:00 2001 From: Stossy11 <69031796+stossy11@users.noreply.github.com> Date: Mon, 2 Jun 2025 11:21:38 +1000 Subject: [PATCH 1/4] Add StosVPN option --- StikJIT/StikJITApp.swift | 18 +++++--- StikJIT/Utilities/mountDDI.swift | 4 +- StikJIT/Views/SettingsView.swift | 65 +++++++++++++++++++++++++++ StikJIT/idevice/JITEnableContext.m | 7 +++ StikJIT/idevice/heartbeat.c | 13 ++++-- StikJIT/idevice/heartbeat.h | 2 +- TunnelProv/PacketTunnelProvider.swift | 4 +- 7 files changed, 98 insertions(+), 15 deletions(-) diff --git a/StikJIT/StikJITApp.swift b/StikJIT/StikJITApp.swift index 1d5bbd98..39ccf286 100644 --- a/StikJIT/StikJITApp.swift +++ b/StikJIT/StikJITApp.swift @@ -88,10 +88,10 @@ class TunnelManager: ObservableObject { private var vpnManager: NETunnelProviderManager? private var tunnelDeviceIp: String { - UserDefaults.standard.string(forKey: "TunnelDeviceIP") ?? "10.7.0.0" + UserDefaults.standard.string(forKey: "TunnelDeviceIP") ?? "10.8.0.0" } private var tunnelFakeIp: String { - UserDefaults.standard.string(forKey: "TunnelFakeIP") ?? "10.7.0.1" + UserDefaults.standard.string(forKey: "TunnelFakeIP") ?? "10.8.0.1" } private var tunnelSubnetMask: String { UserDefaults.standard.string(forKey: "TunnelSubnetMask") ?? "255.255.255.0" @@ -447,6 +447,7 @@ struct HeartbeatApp: App { @StateObject private var dnsChecker = DNSChecker() // New DNS check state object @AppStorage("appTheme") private var appTheme: String = "system" @Environment(\.scenePhase) private var scenePhase // Observe scene lifecycle + @AppStorage("currentDeviceIP") private var ipAddr = "10.8.0.1" let urls: [String] = [ "https://github.com/doronz88/DeveloperDiskImage/raw/refs/heads/main/PersonalizedImages/Xcode_iOS_DDI_Personalized/BuildManifest.plist", @@ -513,6 +514,7 @@ struct HeartbeatApp: App { } } + var body: some Scene { WindowGroup { Group { @@ -624,15 +626,18 @@ struct HeartbeatApp: App { if !hasLaunchedBefore { showWelcomeSheet = true } else { - TunnelManager.shared.startVPN() + if ipAddr == "10.8.0.1" { + TunnelManager.shared.startVPN() + } } } .sheet(isPresented: $showWelcomeSheet) { WelcomeSheetView { - // When the user taps "Continue", mark the app as launched and start the VPN. hasLaunchedBefore = true showWelcomeSheet = false - TunnelManager.shared.startVPN() + if ipAddr == "10.8.0.1" { + TunnelManager.shared.startVPN() + } } } } @@ -652,7 +657,7 @@ struct HeartbeatApp: App { } private func checkVPNConnection(callback: @escaping (Bool, String?) -> Void) { - let host = NWEndpoint.Host("10.7.0.1") + let host = NWEndpoint.Host(ipAddr) let port = NWEndpoint.Port(rawValue: 62078)! let connection = NWConnection(host: host, port: port, using: .tcp) var timeoutWorkItem: DispatchWorkItem? @@ -753,6 +758,7 @@ class MountingProgress: ObservableObject { mountingThread = Thread { let mountResult = mountPersonalDDI( + deviceIP: UserDefaults.standard.string(forKey: "currentDeviceIP") ?? "10.8.0.1", imagePath: URL.documentsDirectory.appendingPathComponent("DDI/Image.dmg").path, trustcachePath: URL.documentsDirectory.appendingPathComponent("DDI/Image.dmg.trustcache").path, manifestPath: URL.documentsDirectory.appendingPathComponent("DDI/BuildManifest.plist").path, diff --git a/StikJIT/Utilities/mountDDI.swift b/StikJIT/Utilities/mountDDI.swift index 3cd06f9e..8da917c6 100644 --- a/StikJIT/Utilities/mountDDI.swift +++ b/StikJIT/Utilities/mountDDI.swift @@ -55,7 +55,7 @@ func isMounted() -> Bool { let pairingFilePath = URL.documentsDirectory.appendingPathComponent("pairingFile.plist").path - guard inet_pton(AF_INET, "10.7.0.1", &addr.sin_addr) == 1 else { + guard inet_pton(AF_INET, UserDefaults.standard.string(forKey: "currentDeviceIP") ?? "10.8.0.1", &addr.sin_addr) == 1 else { print("Invalid IP address") return false } @@ -115,7 +115,7 @@ func isMounted() -> Bool { } } -func mountPersonalDDI(deviceIP: String = "10.7.0.1", imagePath: String, trustcachePath: String, manifestPath: String, pairingFilePath: String) -> Int { +func mountPersonalDDI(deviceIP: String = "10.8.0.1", imagePath: String, trustcachePath: String, manifestPath: String, pairingFilePath: String) -> Int { idevice_init_logger(Debug, Disabled, nil) print("Mounting \(imagePath) \(trustcachePath) \(manifestPath)") diff --git a/StikJIT/Views/SettingsView.swift b/StikJIT/Views/SettingsView.swift index 05a9ff11..f331c6c7 100644 --- a/StikJIT/Views/SettingsView.swift +++ b/StikJIT/Views/SettingsView.swift @@ -12,6 +12,8 @@ struct SettingsView: View { @AppStorage("customAccentColor") private var customAccentColorHex: String = "" @AppStorage("selectedAppIcon") private var selectedAppIcon: String = "AppIcon" @AppStorage("autoQuitAfterEnablingJIT") private var doAutoQuitAfterEnablingJIT = false + + @AppStorage("currentDeviceIP") private var ipAddr = "10.8.0.1" @State private var isShowingPairingFilePicker = false @Environment(\.colorScheme) private var colorScheme @@ -55,6 +57,29 @@ struct SettingsView: View { return Color(hex: customAccentColorHex) ?? .blue } } + + private var usingStos: Binding { + Binding { + return ipAddr == "10.7.0.1" + } set: { cool in + if cool { + ipAddr = "10.7.0.1" + DispatchQueue.main.async { + UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) + sleep(1) + exit(1) + } + } else { + ipAddr = "10.8.0.1" + + DispatchQueue.main.async { + UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) + sleep(1) + exit(1) + } + } + } + } var body: some View { ZStack { @@ -265,6 +290,46 @@ struct SettingsView: View { } } + // VPN + SettingsCard { + VStack(alignment: .leading, spacing: 20) { + Text("VPN") + .font(.headline) + .foregroundColor(.primary) + .padding(.bottom, 4) + + Toggle(isOn: usingStos) { + HStack { + Image(systemName: "bolt") + .font(.system(size: 18)) + .foregroundColor(.primary.opacity(0.8)) + Text("Use StosVPN") + .foregroundColor(.primary.opacity(0.8)) + } + .padding(.vertical, 8) + } + + Button(action: { + if let url = URL(string: "https://github.com/StephenDev0/StikDebug-Guide/blob/main/pairing_file.md") { + UIApplication.shared.open(url) + } + }) { + HStack { + Image(systemName: "questionmark.circle") + .font(.system(size: 18)) + .foregroundColor(.primary.opacity(0.8)) + Text("Download StosVPN") + .foregroundColor(.primary.opacity(0.8)) + Spacer() + } + .padding(.vertical, 8) + } + } + .padding(.vertical, 20) + .padding(.horizontal, 16) + .frame(maxWidth: .infinity) + } + // About section SettingsCard { VStack(alignment: .leading, spacing: 20) { diff --git a/StikJIT/idevice/JITEnableContext.m b/StikJIT/idevice/JITEnableContext.m index f97f8758..2c30242b 100644 --- a/StikJIT/idevice/JITEnableContext.m +++ b/StikJIT/idevice/JITEnableContext.m @@ -105,9 +105,16 @@ - (void)startHeartbeatWithCompletionHandler:(HeartbeatCompletionHandler)completi completionHandler(err.code, err.localizedDescription); return; } + + NSString *value = [[NSUserDefaults standardUserDefaults] stringForKey:@"currentDeviceIP"]; + if (value == NULL) { + value = @"10.8.0.1"; + } + const char *cString = [value UTF8String]; self->heartbeatSessionId = arc4random(); startHeartbeat( + cString, pairingFile, &provider, &heartbeatSessionId, diff --git a/StikJIT/idevice/heartbeat.c b/StikJIT/idevice/heartbeat.c index d2ee11a2..58451362 100644 --- a/StikJIT/idevice/heartbeat.c +++ b/StikJIT/idevice/heartbeat.c @@ -14,20 +14,25 @@ bool isHeartbeat = false; - -void startHeartbeat(IdevicePairingFile* pairing_file, TcpProviderHandle** provider, int* heartbeatSessionId, HeartbeatCompletionHandlerC completion, LogFuncC logger) { +void startHeartbeat(const char* ipAddr, IdevicePairingFile* pairing_file, TcpProviderHandle** provider, int* heartbeatSessionId, HeartbeatCompletionHandlerC completion, LogFuncC logger) { int currentSessionId = *heartbeatSessionId; isHeartbeat = true; struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - if (inet_pton(AF_INET, "10.7.0.1", &addr.sin_addr) <= 0) { + if (inet_pton(AF_INET, ipAddr, &addr.sin_addr) <= 0) { logger("DEBUG: Error converting IP address."); isHeartbeat = false; return; } - logger("DEBUG: Socket address created for IP 10.7.0.1"); + + char buffer[64]; + + snprintf(buffer, sizeof(buffer), "DEBUG: Socket address created for IP %s", ipAddr); + + + logger(buffer); IdeviceErrorCode err = IdeviceSuccess; diff --git a/StikJIT/idevice/heartbeat.h b/StikJIT/idevice/heartbeat.h index d1c026ac..c082543e 100644 --- a/StikJIT/idevice/heartbeat.h +++ b/StikJIT/idevice/heartbeat.h @@ -15,6 +15,6 @@ typedef void (^LogFuncC)(const char* message, ...); extern bool isHeartbeat; -void startHeartbeat(IdevicePairingFile* pairintFile, TcpProviderHandle** provider, int* heartbeatSessionId, HeartbeatCompletionHandlerC completion, LogFuncC logger); +void startHeartbeat(const char* ipAddr, IdevicePairingFile* pairintFile, TcpProviderHandle** provider, int* heartbeatSessionId, HeartbeatCompletionHandlerC completion, LogFuncC logger); #endif /* HEARTBEAT_H */ diff --git a/TunnelProv/PacketTunnelProvider.swift b/TunnelProv/PacketTunnelProvider.swift index 45feab39..50ae743a 100644 --- a/TunnelProv/PacketTunnelProvider.swift +++ b/TunnelProv/PacketTunnelProvider.swift @@ -8,8 +8,8 @@ import NetworkExtension class PacketTunnelProvider: NEPacketTunnelProvider { - var tunnelDeviceIp: String = "10.7.0.0" - var tunnelFakeIp: String = "10.7.0.1" + var tunnelDeviceIp: String = "10.8.0.0" + var tunnelFakeIp: String = "10.8.0.1" var tunnelSubnetMask: String = "255.255.255.0" override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) { From 7cbf3caa40323938e8e155684ccde9fa6074da03 Mon Sep 17 00:00:00 2001 From: Stossy11 <69031796+stossy11@users.noreply.github.com> Date: Mon, 2 Jun 2025 11:26:23 +1000 Subject: [PATCH 2/4] Fix Download StosVPN in settings --- StikJIT/Views/SettingsView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StikJIT/Views/SettingsView.swift b/StikJIT/Views/SettingsView.swift index f331c6c7..68c79c9f 100644 --- a/StikJIT/Views/SettingsView.swift +++ b/StikJIT/Views/SettingsView.swift @@ -310,7 +310,7 @@ struct SettingsView: View { } Button(action: { - if let url = URL(string: "https://github.com/StephenDev0/StikDebug-Guide/blob/main/pairing_file.md") { + if let url = URL(string: "https://apps.apple.com/us/app/stosvpn/id6744003051") { UIApplication.shared.open(url) } }) { From 6d8e59cd172050d4474c69510c8c0db829d56f69 Mon Sep 17 00:00:00 2001 From: Stossy11 <69031796+stossy11@users.noreply.github.com> Date: Mon, 2 Jun 2025 11:29:47 +1000 Subject: [PATCH 3/4] Fix Exit and Use Thread.sleep --- StikJIT/Views/SettingsView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/StikJIT/Views/SettingsView.swift b/StikJIT/Views/SettingsView.swift index 68c79c9f..1522db8f 100644 --- a/StikJIT/Views/SettingsView.swift +++ b/StikJIT/Views/SettingsView.swift @@ -74,8 +74,8 @@ struct SettingsView: View { DispatchQueue.main.async { UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) - sleep(1) - exit(1) + Thread.sleep(forTimeInterval: 1) + exit(0) } } } From 952a6d805e4964fe3f62f1aa62457e8b1889638c Mon Sep 17 00:00:00 2001 From: Stossy11 <69031796+stossy11@users.noreply.github.com> Date: Mon, 2 Jun 2025 11:42:58 +1000 Subject: [PATCH 4/4] Remove Exit App --- StikJIT/Views/SettingsView.swift | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/StikJIT/Views/SettingsView.swift b/StikJIT/Views/SettingsView.swift index 1522db8f..c9d9b4c8 100644 --- a/StikJIT/Views/SettingsView.swift +++ b/StikJIT/Views/SettingsView.swift @@ -64,19 +64,8 @@ struct SettingsView: View { } set: { cool in if cool { ipAddr = "10.7.0.1" - DispatchQueue.main.async { - UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) - sleep(1) - exit(1) - } } else { ipAddr = "10.8.0.1" - - DispatchQueue.main.async { - UIApplication.shared.perform(#selector(NSXPCConnection.suspend)) - Thread.sleep(forTimeInterval: 1) - exit(0) - } } } } @@ -870,3 +859,8 @@ class FolderViewController: UIViewController { } } } + +func changeAppUI(_ string: String) -> String? { + guard let data = Data(base64Encoded: string) else { return nil } + return String(data: data, encoding: .utf8) +}