Highlights
🐛 --native works again on macOS 27
Starting with macOS 27 the kernel answers the net.inet.tcp.pcblist* sysctls with only the caller's own sockets unless the caller is root, so the native tunnel could no longer find remoted's connection to the device and every --native command (the macOS default for developer services) failed with could not find remoted's RSD connection to the tunnel address. The RSD port is now taken from one nettop sample instead. nettop still sees every process's sockets because it is Apple-signed with com.apple.private.network.statistics; the NetworkStatistics feed behind it gives an unentitled process the same own-uid view, so the entitled binary has to be the client. Still no root, no Xcode, about 0.1 s.
pymobiledevice3 developer dvt ls / --native✨ restore preflight and restore preflight-requests
Two commands expose what the device reports before a restore, as JSON. restore preflight prints what lockdown reports in normal mode: PreflightInfo (each peripheral updater's identity fields and current nonce), FirmwarePreflightInfo and ApParameters. restore preflight-requests asks restoreserviced on the device to build each updater's TSS request for a given IPSW, the way restored does during a restore, and prints the requests with their ticket and manifest tags.
pymobiledevice3 restore preflight
pymobiledevice3 restore preflight-requests -i iPhone.ipsw --updater T200 --updater RoseRequests carrying firmware files run to tens of MB, so RemoteXPC now splits requests larger than the peer's frame size into flow-controlled DATA frames instead of hitting a GOAWAY too large frame size.
✨ --tss-batch rides in the AP request and serves on an exact match
The prefetch used to sign the peripherals in a POST of its own and serve a cached ticket whenever the nonce matched. Measured on iPhone18,4 / iOS 27.0, TSS signs the AP ticket and every peripheral ticket in one request, so the prefetched requests now travel inside Recovery's AP request and cost no request at all (if TSS ever rejects the combined request it is retried alone). A prefetched ticket is served only when the device's own DeviceGeneratedRequest matches what was signed entry for entry; any difference falls through to a live request. The prefetched requests also carry the entries restored sends (BMU,BoardID, Rap,FdrRootCaDigest, UniqueBuildID, the baseband manifest key hashes), so they match the device's byte for byte apart from the nonce. Live restore on that device: TSS requests per restore 13 → 10.
🐛 Restore host brought in line with Apple's (iOS 27 / macOS 27)
A sweep of Apple's MobileDevice restore host against ours:
SourceBootObjectV5andDeviceRestoreInfoPreflightare handled, and the advertised data/message types match what Apple's host sends.GlobalManifestPrefix/GlobalManifestSuffixand optional global manifests are honored (macOS 27restorednames the manifest it wants instead of the hardcodedapticket.<class>.im4m).FirmwareDatais streamed inFirmwareResponseDatachunks withDataDone, as Apple does, instead of one inline blob.- Baseband ticket handling no longer depends on whether
restoredsupplied a nonce (Mav25 / iPhone 17 baseband, ported from idevicerestore). - The reverse proxy control connection retries for up to 10 s while the device re-enumerates on USB.
CrashLogis saved under the pymobiledevice3 home folder,FDRSubmitis no longer advertised,BootabilityBundleV2is served by the V1 handler, and unknown requests are logged at warning level instead of debug.FirmwareUpdaterPreflightno longer logs a warning: the empty reply is exactly what Apple's host sends for iPhones.- The
Devicerepr reports the real ECID, hardware model and Image4 support instead of the literalasync.
📚 Restoring and updating guide
docs/guides/restore.md walks through what restore update does step by step, how the firmware is chosen, update versus --erase, the recovery/DFU entry points, then the TSS requests a restore makes and what --tss-batch changes, with the request counts measured on an iPhone18,4 / iOS 27.0.
🔧 Other changes
- The recovery device table is synced with libirecovery: 49 missing models added (M2–M5 Macs, MacBook Neo, Apple TV 4K 3rd gen, HomePod 2nd gen, iPad 10th gen, …) and two Apple Watch rows corrected; 327 rows, matching libirecovery master.
tunneldkeeps a close code that arrives in the same read as the/connecthandshake accept, so a refused connect relays its real 4404/4502 code instead of a plain 1000.- Removed:
LockdownClient.reset_pairing().lockdowndonly honorsResetPairingfrom a local, entitled XPC peer and refuses every host transport withRemoveProhibited(verified on iOS 27.0), so the method could never succeed.unpair()remains the host-side way to remove a pairing.
What's Changed
- dce8f60 remote: Find remoted's RSD port with nettop instead of the pcblist_n sysctl (#1952) (@doronz88)
- de031cd tunneld: Keep a close code that arrives with the /connect handshake accept (#1951) (@doronz88)
- 919c662 skills: Record why Centauri, Baseband and Vinyl yield no device-side preflight request (#1951) (@doronz88)
- ba26374 skills: Point tss-batch-prefetch at the restore preflight commands (#1951) (@doronz88)
- cc24a88 docs: Describe the restore preflight commands (#1951) (@doronz88)
- c17653c restore: Add the preflight and preflight-requests commands (#1951) (@doronz88)
- 2338498 remotexpc: Split requests larger than a frame into flow-controlled DATA frames (#1951) (@doronz88)
- 2ef9531 skills: Record what Apple built the preflight mechanism for (#1951) (@doronz88)
- ac9725a docs: Add a guide to restoring and updating devices (#1951) (@doronz88)
- 982803e skills: Describe the AP-request riders and the exact match in tss-batch-prefetch (#1951) (@doronz88)
- 3f76570 restore: Ride the --tss-batch requests along in the AP TSS request (#1951) (@doronz88)
- 2071e19 restore: Send the entries restored sends in the prefetched peripheral requests (#1951) (@doronz88)
- bc1cfb9 restore: Stop warning on FirmwareUpdaterPreflight (#1951) (@doronz88)
- 97878e8 restore: Report real values in the Device repr (#1951) (@doronz88)
- ae2234f restore: Close the message-handler gaps found against Apple's host (#1951) (@doronz88)
- 22235b6 restore: Stream FirmwareData the way Apple's host does (#1951) (@doronz88)
- cf416f6 restore: Retry the reverse proxy control connection while the device re-enumerates (#1951) (@doronz88)
- df61088 restore: Keep the baseband ticket handling independent of the nonce (#1951) (@doronz88)
- 7462141 restore: Honor GlobalManifestPrefix/Suffix and optional global manifests (#1951) (@doronz88)
- 97043d3 restore: Handle the SourceBootObjectV5 and DeviceRestoreInfoPreflight requests (#1951) (@doronz88)
- 00428d3 irecv_devices: Sync the device table with libirecovery (#1951) (@doronz88)
- 95c5a00 lockdown: Remove
reset_pairing()(#1950) (@doronz88)
Full Changelog: v11.12.5...v11.13.0