From adb91439e4e90c7428b4355c316588725645b158 Mon Sep 17 00:00:00 2001 From: mahee96 <47920326+mahee96@users.noreply.github.com> Date: Mon, 2 Mar 2026 07:33:51 +0530 Subject: [PATCH] minimuxer: added dynamic lookup of peer for utun(VPN) when not in P2P which is required for sidestore --- Dependencies/minimuxer | 2 +- SideStore/IfManager.swift | 132 ------------------------------- SideStore/MinimuxerWrapper.swift | 115 +++++++++++++-------------- 3 files changed, 57 insertions(+), 192 deletions(-) delete mode 100644 SideStore/IfManager.swift diff --git a/Dependencies/minimuxer b/Dependencies/minimuxer index 40ccd42d..8d02a7b6 160000 --- a/Dependencies/minimuxer +++ b/Dependencies/minimuxer @@ -1 +1 @@ -Subproject commit 40ccd42d1a49c9d39d0193c69b63fe83c96b6c38 +Subproject commit 8d02a7b62ed783bcb7656fab82a0a65fc4ba02da diff --git a/SideStore/IfManager.swift b/SideStore/IfManager.swift deleted file mode 100644 index edddb681..00000000 --- a/SideStore/IfManager.swift +++ /dev/null @@ -1,132 +0,0 @@ -// -// IfManager.swift -// AltStore -// -// Created by ny on 2/27/26. -// Copyright © 2026 SideStore. All rights reserved. -// - -import Foundation -import Network - -fileprivate func uti(_ uint: UInt32) -> String? { - var buf = [CChar](repeating: 0, count: Int(NI_MAXHOST)) - var addr = in_addr(s_addr: uint.bigEndian) - guard inet_ntop(AF_INET, &addr, &buf, UInt32(INET_ADDRSTRLEN)) != nil, - let str = String(utf8String: buf) else { return nil } - return str -} - -fileprivate func socktouint(_ sock: inout sockaddr) -> UInt32 { - var buf = [CChar](repeating: 0, count: Int(NI_MAXHOST)) - guard getnameinfo(&sock, socklen_t(sock.sa_len), &buf, socklen_t(buf.count), nil, socklen_t(0), NI_NUMERICHOST) == 0, - let name = String(utf8String: buf) else { - return 0 - } - var addr = in_addr() - guard name.withCString({ cString in - inet_pton(AF_INET, cString, &addr) - }) == 1 else { return 0 } - return addr.s_addr.bigEndian -} - -public struct NetInfo: Hashable, CustomStringConvertible { - public let name: String - public let hostIP: String - public let destIP: String - public let maskIP: String - - private let host: UInt32 - private let dest: UInt32 - private let mask: UInt32 - - init(name: String, host: UInt32, dest: UInt32, mask: UInt32) { - self.name = name - self.host = host - self.dest = dest - self.mask = mask - self.hostIP = uti(host) ?? "10.7.0.0" - self.destIP = uti(dest) ?? "10.7.0.1" - self.maskIP = uti(mask) ?? "255.255.255.0" - } - - init?(_ ifaddr: ifaddrs) { - guard - let ianame = String(utf8String: ifaddr.ifa_name) - else { return nil } - - let host = socktouint(&ifaddr.ifa_addr.pointee) - let dest = socktouint(&ifaddr.ifa_dstaddr.pointee) - let mask = socktouint(&ifaddr.ifa_netmask.pointee) - - self.init(name: ianame, host: host, dest: dest, mask: mask) - } - - // computed networking values (still numeric internally) - public var minIP: UInt32 { host & mask } - public var maxIP: UInt32 { host | ~mask } - - public var minIPString: String { uti(minIP) ?? "nil" } - public var maxIPString: String { uti(maxIP) ?? "nil" } - - public var description: String { - "\(name) | ip=\(hostIP) dest=\(destIP) mask=\(maskIP) range=\(minIPString)-\(maxIPString)" - } -} - -final class IfManager: Sendable { - public static let shared = IfManager() - nonisolated(unsafe) private(set) var addrs: Set = Set() - - private init() { - self.addrs = IfManager.query() - } - - - public func query() { - addrs = IfManager.query() - } - - private static func query() -> Set { - var addrs = Set() - var head: UnsafeMutablePointer? = nil - guard getifaddrs(&head) == 0, let first = head else { return addrs } - defer { freeifaddrs(head) } - - var cursor: UnsafeMutablePointer? = first - while let current = cursor { - // we only want v4 interfaces that aren't loopback and aren't masked 255.255.255.255 - let entry = current.pointee - let flags = Int32(entry.ifa_flags) - - let isIPv4 = entry.ifa_addr.pointee.sa_family == UInt8(AF_INET) - let isActive = (flags & (IFF_UP | IFF_RUNNING | IFF_LOOPBACK)) == (IFF_UP | IFF_RUNNING) - - if isIPv4, isActive, let info = NetInfo(entry), info.maskIP != "255.255.255.255" { - addrs.insert(info) - } - - cursor = entry.ifa_next - } - return addrs - } - - private var nextLAN: NetInfo? { - addrs.first { $0.name.starts(with: "en") } - } - - var nextProbableSideVPN: NetInfo? { - // try old 10.7.0.1 first, then fallback to next v4 - // user should only be connected to StosVPN/LocalDevVPN - addrs.first { - $0.hostIP == "10.7.0.1" || - $0.name.starts(with: "utun") - } - } - - var sideVPNPatched: Bool { - nextLAN?.maskIP == nextProbableSideVPN?.maskIP && - nextLAN?.maxIP == nextProbableSideVPN?.maxIP - } -} - diff --git a/SideStore/MinimuxerWrapper.swift b/SideStore/MinimuxerWrapper.swift index 78a087a2..aa4a212b 100644 --- a/SideStore/MinimuxerWrapper.swift +++ b/SideStore/MinimuxerWrapper.swift @@ -9,150 +9,147 @@ import Foundation import Minimuxer var isMinimuxerReady: Bool { + var result = true #if targetEnvironment(simulator) - print("isMinimuxerReady = true on simulator") - return true + print("[SideStore] isMinimuxerReady = true on simulator") #else - IfManager.shared.query() - let dest = IfManager.shared.nextProbableSideVPN?.destIP - var result = false - if #available(iOS 26.4, *) { - result = Minimuxer.ready(ifaddr: dest) && IfManager.shared.sideVPNPatched - } else { - result = Minimuxer.ready(ifaddr: dest) - } - print("isMinimuxerReady = \(result)") + result = Minimuxer.ready() + print("[SideStore] isMinimuxerReady = \(result)") + #endif return result +} + + +func targetMinimuxerAddress() { + defer { print("[SideStore] targetMinimuxerAddress() completed") } + #if targetEnvironment(simulator) + print("[SideStore] targetMinimuxerAddress() is no-op on simulator") + #else + print("[SideStore] targetMinimuxerAddress() invoked") + Minimuxer.updateUsbMuxdAddr() #endif } func minimuxerStartWithLogger(_ pairingFile: String, _ logPath: String, _ loggingEnabled: Bool) throws { - defer { print("minimuxerStartWithLogger(pairingFile, logPath, dest, loggingEnabled) completed") } + defer { print("[SideStore] minimuxerStartWithLogger(pairingFile, logPath, dest, loggingEnabled) completed") } #if targetEnvironment(simulator) - print("minimuxerStartWithLogger(pairingFile, logPath, loggingEnabled) is no-op on simulator") + print("[SideStore] minimuxerStartWithLogger(pairingFile, logPath, loggingEnabled) is no-op on simulator") #else -// IfManager.shared.query() -// let dest = IfManager.shared.nextProbableSideVPN?.destIP - print("minimuxerStartWithLogger(pairingFile, logPath, dest, loggingEnabled) invoked") - try Minimuxer.startWithLogger(pairingFile: pairingFile, logPath: logPath, ifaddr: nil, isConsoleLoggingEnabled: loggingEnabled) - #endif -} - -func targetMinimuxerAddress() { - defer { print("targetMinimuxerAddress() completed") } - #if targetEnvironment(simulator) - print("targetMinimuxerAddress() is no-op on simulator") - #else - print("targetMinimuxerAddress() invoked") - Minimuxer.targetMinimuxerAddress() + // observe network route changes (and update device endpoint from vpn(utun)) + NetworkObserver.shared.start() + + print("[SideStore] minimuxerStartWithLogger(pairingFile, logPath, dest, loggingEnabled) invoked") + try Minimuxer.startWithLogger(pairingFile: pairingFile, + logPath: logPath, + isConsoleLoggingEnabled: loggingEnabled) #endif } func installProvisioningProfiles(_ profileData: Data) throws { - defer { print("installProvisioningProfiles(profileData) completed") } + defer { print("[SideStore] installProvisioningProfiles(profileData) completed") } #if targetEnvironment(simulator) - print("installProvisioningProfiles(profileData) is no-op on simulator") + print("[SideStore] installProvisioningProfiles(profileData) is no-op on simulator") #else - print("installProvisioningProfiles(profileData) invoked") + print("[SideStore] installProvisioningProfiles(profileData) invoked") try Minimuxer.installProvisioningProfile(profile: profileData) #endif } func removeProvisioningProfile(_ id: String) throws { - defer { print("removeProvisioningProfile(id) completed") } + defer { print("[SideStore] removeProvisioningProfile(id) completed") } #if targetEnvironment(simulator) - print("removeProvisioningProfile(id) is no-op on simulator") + print("[SideStore] removeProvisioningProfile(id) is no-op on simulator") #else - print("removeProvisioningProfile(id) invoked") + print("[SideStore] removeProvisioningProfile(id) invoked") try Minimuxer.removeProvisioningProfile(id: id) #endif } func removeApp(_ bundleId: String) throws { - defer { print("removeApp(bundleId) completed") } + defer { print("[SideStore] removeApp(bundleId) completed") } #if targetEnvironment(simulator) - print("removeApp(bundleId) is no-op on simulator") + print("[SideStore] removeApp(bundleId) is no-op on simulator") #else - print("removeApp(bundleId) invoked") + print("[SideStore] removeApp(bundleId) invoked") try Minimuxer.removeApp(bundleId: bundleId) #endif } func yeetAppAFC(_ bundleId: String, _ rawBytes: Data) throws { - defer { print("yeetAppAFC(bundleId, rawBytes) completed") } + defer { print("[SideStore] yeetAppAFC(bundleId, rawBytes) completed") } #if targetEnvironment(simulator) - print("yeetAppAFC(bundleId, rawBytes) is no-op on simulator") + print("[SideStore] yeetAppAFC(bundleId, rawBytes) is no-op on simulator") #else - print("yeetAppAFC(bundleId, rawBytes) invoked") + print("[SideStore] yeetAppAFC(bundleId, rawBytes) invoked") try Minimuxer.yeetAppAfc(bundleId: bundleId, ipaBytes: rawBytes) #endif } func installIPA(_ bundleId: String) throws { - defer { print("installIPA(bundleId) completed") } + defer { print("[SideStore] installIPA(bundleId) completed") } #if targetEnvironment(simulator) - print("installIPA(bundleId) is no-op on simulator") + print("[SideStore] installIPA(bundleId) is no-op on simulator") #else - print("installIPA(bundleId) invoked") + print("[SideStore] installIPA(bundleId) invoked") try Minimuxer.installIpa(bundleId: bundleId) #endif } func fetchUDID() -> String? { - defer { print("fetchUDID() completed") } + defer { print("[SideStore] fetchUDID() completed") } #if targetEnvironment(simulator) - print("fetchUDID() is no-op on simulator") + print("[SideStore] fetchUDID() is no-op on simulator") return "XXXXX-XXXX-XXXXX-XXXX" #else - print("fetchUDID() invoked") + print("[SideStore] fetchUDID() invoked") return Minimuxer.fetchUDID() #endif } func debugApp(_ appId: String) throws { - defer { print("debugApp(appId) completed") } + defer { print("[SideStore] debugApp(appId) completed") } #if targetEnvironment(simulator) - print("debugApp(appId) is no-op on simulator") + print("[SideStore] debugApp(appId) is no-op on simulator") #else - print("debugApp(appId) invoked") + print("[SideStore] debugApp(appId) invoked") try Minimuxer.debugApp(appId: appId) #endif } func attachDebugger(_ pid: UInt32) throws { - defer { print("attachDebugger(pid) completed") } + defer { print("[SideStore] attachDebugger(pid) completed") } #if targetEnvironment(simulator) - print("attachDebugger(pid) is no-op on simulator") + print("[SideStore] attachDebugger(pid) is no-op on simulator") #else - print("attachDebugger(pid) invoked") + print("[SideStore] attachDebugger(pid) invoked") try Minimuxer.attachDebugger(pid: pid) #endif } func startAutoMounter(_ docsPath: String) { - defer { print("startAutoMounter(docsPath) completed") } + defer { print("[SideStore] startAutoMounter(docsPath) completed") } #if targetEnvironment(simulator) - print("startAutoMounter(docsPath) is no-op on simulator") + print("[SideStore] startAutoMounter(docsPath) is no-op on simulator") #else - print("startAutoMounter(docsPath) invoked") + print("[SideStore] startAutoMounter(docsPath) invoked") Minimuxer.startAutoMounter(docsPath: docsPath) #endif } func dumpProfiles(_ docsPath: String) throws -> String { - defer { print("dumpProfiles(docsPath) completed") } + defer { print("[SideStore] dumpProfiles(docsPath) completed") } #if targetEnvironment(simulator) - print("dumpProfiles(docsPath) is no-op on simulator") + print("[SideStore] dumpProfiles(docsPath) is no-op on simulator") return "" #else - print("dumpProfiles(docsPath) invoked") + print("[SideStore] dumpProfiles(docsPath) invoked") return try Minimuxer.dumpProfiles(docsPath: docsPath) #endif } func setMinimuxerDebug(_ debug: Bool) { - defer { print("setMinimuxerDebug(debug) completed") } - print("setMinimuxerDebug(debug) invoked") + defer { print("[SideStore] setMinimuxerDebug(debug) completed") } + print("[SideStore] setMinimuxerDebug(debug) invoked") Minimuxer.setDebug(debug) }