diff --git a/idevice/src/core_device_proxy.rs b/idevice/src/core_device_proxy.rs index c0a2f95..f059da9 100644 --- a/idevice/src/core_device_proxy.rs +++ b/idevice/src/core_device_proxy.rs @@ -1,14 +1,11 @@ // Jackson Coxson -use crate::{Idevice, IdeviceError}; +use crate::{lockdownd::LockdowndClient, Idevice, IdeviceError, IdeviceService}; use byteorder::{BigEndian, WriteBytesExt}; use serde::{Deserialize, Serialize}; use std::io::{self, Write}; -pub const SERVCE_NAME: &str = "com.apple.internal.devicecompute.CoreDeviceProxy"; -const DEFAULT_MTU: u32 = 16000; - #[derive(Debug, PartialEq)] pub struct CDTunnelPacket { body: Vec, @@ -67,6 +64,28 @@ pub struct CoreDeviceProxy { pub mtu: u32, } +impl IdeviceService for CoreDeviceProxy { + fn service_name() -> &'static str { + "com.apple.internal.devicecompute.CoreDeviceProxy" + } + + async fn connect( + provider: &impl crate::provider::IdeviceProvider, + ) -> Result { + let mut lockdown = LockdowndClient::connect(provider).await?; + let (port, ssl) = lockdown.start_service(Self::service_name()).await?; + + let mut idevice = provider.connect(port).await?; + if ssl { + idevice + .start_session(&provider.get_pairing_file().await?) + .await?; + } + + Ok(Self::new(idevice)) + } +} + #[derive(Serialize)] struct HandshakeRequest { #[serde(rename = "type")] @@ -94,17 +113,19 @@ pub struct HandshakeResponse { } impl CoreDeviceProxy { + const DEFAULT_MTU: u32 = 16000; + pub fn new(idevice: Idevice) -> Self { Self { idevice, - mtu: DEFAULT_MTU, + mtu: Self::DEFAULT_MTU, } } pub async fn establish_tunnel(&mut self) -> Result { let req = HandshakeRequest { packet_type: "clientHandshakeRequest".to_string(), - mtu: DEFAULT_MTU, + mtu: Self::DEFAULT_MTU, }; let req = CDTunnelPacket::serialize(&CDTunnelPacket { diff --git a/idevice/src/heartbeat.rs b/idevice/src/heartbeat.rs index a2cd33c..acf07f5 100644 --- a/idevice/src/heartbeat.rs +++ b/idevice/src/heartbeat.rs @@ -1,12 +1,34 @@ // Jackson Coxson // Abstractions for the heartbeat service on iOS -use crate::{Idevice, IdeviceError}; +use crate::{lockdownd::LockdowndClient, Idevice, IdeviceError, IdeviceService}; pub struct HeartbeatClient { pub idevice: Idevice, } +impl IdeviceService for HeartbeatClient { + fn service_name() -> &'static str { + "com.apple.mobile.heartbeat" + } + + async fn connect( + provider: &impl crate::provider::IdeviceProvider, + ) -> Result { + let mut lockdown = LockdowndClient::connect(provider).await?; + let (port, ssl) = lockdown.start_service(Self::service_name()).await?; + + let mut idevice = provider.connect(port).await?; + if ssl { + idevice + .start_session(&provider.get_pairing_file().await?) + .await?; + } + + Ok(Self { idevice }) + } +} + impl HeartbeatClient { pub fn new(idevice: Idevice) -> Self { Self { idevice } diff --git a/idevice/src/installation_proxy.rs b/idevice/src/installation_proxy.rs index 4f07907..5c420b0 100644 --- a/idevice/src/installation_proxy.rs +++ b/idevice/src/installation_proxy.rs @@ -3,12 +3,34 @@ use std::collections::HashMap; -use crate::{Idevice, IdeviceError}; +use crate::{lockdownd::LockdowndClient, Idevice, IdeviceError, IdeviceService}; pub struct InstallationProxyClient { pub idevice: Idevice, } +impl IdeviceService for InstallationProxyClient { + fn service_name() -> &'static str { + "com.apple.mobile.installation_proxy" + } + + async fn connect( + provider: &impl crate::provider::IdeviceProvider, + ) -> Result { + let mut lockdown = LockdowndClient::connect(provider).await?; + let (port, ssl) = lockdown.start_service(Self::service_name()).await?; + + let mut idevice = provider.connect(port).await?; + if ssl { + idevice + .start_session(&provider.get_pairing_file().await?) + .await?; + } + + Ok(Self::new(idevice)) + } +} + impl InstallationProxyClient { pub fn new(idevice: Idevice) -> Self { Self { idevice } diff --git a/idevice/src/lib.rs b/idevice/src/lib.rs index df59f00..8bfc2ce 100644 --- a/idevice/src/lib.rs +++ b/idevice/src/lib.rs @@ -20,6 +20,7 @@ pub mod xpc; use log::{debug, error}; use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode}; +use provider::IdeviceProvider; use std::io::{self, BufWriter}; use thiserror::Error; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; @@ -27,6 +28,13 @@ use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; pub trait ReadWrite: AsyncRead + AsyncWrite + Unpin + Send + Sync + std::fmt::Debug {} impl ReadWrite for T {} +pub trait IdeviceService: Sized { + fn service_name() -> &'static str; + fn connect( + provider: &impl IdeviceProvider, + ) -> impl std::future::Future> + Send; +} + pub type IdeviceSocket = Box; pub struct Idevice { diff --git a/idevice/src/lockdownd.rs b/idevice/src/lockdownd.rs index 3f3d0f9..964e268 100644 --- a/idevice/src/lockdownd.rs +++ b/idevice/src/lockdownd.rs @@ -1,17 +1,28 @@ // Jackson Coxson // Abstractions for lockdownd -pub const LOCKDOWND_PORT: u16 = 62078; - use log::error; use serde::{Deserialize, Serialize}; -use crate::{pairing_file, Idevice, IdeviceError}; +use crate::{pairing_file, Idevice, IdeviceError, IdeviceService}; pub struct LockdowndClient { pub idevice: crate::Idevice, } +impl IdeviceService for LockdowndClient { + fn service_name() -> &'static str { + "com.apple.mobile.lockdown" + } + + async fn connect( + provider: &impl crate::provider::IdeviceProvider, + ) -> Result { + let idevice = provider.connect(Self::LOCKDOWND_PORT).await?; + Ok(Self { idevice }) + } +} + #[derive(Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] struct LockdowndRequest { @@ -21,6 +32,8 @@ struct LockdowndRequest { } impl LockdowndClient { + pub const LOCKDOWND_PORT: u16 = 62078; + pub fn new(idevice: Idevice) -> Self { Self { idevice } } diff --git a/idevice/src/mounter.rs b/idevice/src/mounter.rs index 7cea6c2..1ed1e6f 100644 --- a/idevice/src/mounter.rs +++ b/idevice/src/mounter.rs @@ -1,11 +1,33 @@ // Jackson Coxson -use crate::{Idevice, IdeviceError}; +use crate::{lockdownd::LockdowndClient, Idevice, IdeviceError, IdeviceService}; pub struct ImageMounter { idevice: Idevice, } +impl IdeviceService for ImageMounter { + fn service_name() -> &'static str { + "com.apple.mobile.mobile_image_mounter" + } + + async fn connect( + provider: &impl crate::provider::IdeviceProvider, + ) -> Result { + let mut lockdown = LockdowndClient::connect(provider).await?; + let (port, ssl) = lockdown.start_service(Self::service_name()).await?; + + let mut idevice = provider.connect(port).await?; + if ssl { + idevice + .start_session(&provider.get_pairing_file().await?) + .await?; + } + + Ok(Self { idevice }) + } +} + impl ImageMounter { pub fn new(idevice: Idevice) -> Self { Self { idevice } diff --git a/idevice/src/provider.rs b/idevice/src/provider.rs index d617f10..12e046d 100644 --- a/idevice/src/provider.rs +++ b/idevice/src/provider.rs @@ -4,19 +4,24 @@ use std::net::{IpAddr, SocketAddr}; use tokio::net::TcpStream; -use crate::{usbmuxd::UsbmuxdAddr, Idevice, IdeviceError}; +use crate::{pairing_file::PairingFile, usbmuxd::UsbmuxdAddr, Idevice, IdeviceError}; -pub trait IdeviceProvider { +pub trait IdeviceProvider: Unpin + Send + Sync + std::fmt::Debug { // https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html#is-it-okay-to-use-async-fn-in-traits-what-are-the-limitations fn connect( &self, port: u16, ) -> impl std::future::Future> + Send; fn label(&self) -> &str; + fn get_pairing_file( + &self, + ) -> impl std::future::Future> + Send; } +#[derive(Debug)] pub struct TcpProvider { addr: IpAddr, + pairing_file: PairingFile, label: String, } @@ -29,12 +34,18 @@ impl IdeviceProvider for TcpProvider { fn label(&self) -> &str { self.label.as_str() } + + async fn get_pairing_file(&self) -> Result { + Ok(self.pairing_file.clone()) + } } #[cfg(feature = "usbmuxd")] +#[derive(Debug)] pub struct UsbmuxdProvider { addr: UsbmuxdAddr, tag: u32, + udid: String, device_id: u32, label: String, } @@ -51,4 +62,9 @@ impl IdeviceProvider for UsbmuxdProvider { fn label(&self) -> &str { self.label.as_str() } + + async fn get_pairing_file(&self) -> Result { + let mut usbmuxd = self.addr.connect(self.tag).await?; + usbmuxd.get_pair_record(&self.udid).await + } } diff --git a/idevice/src/usbmuxd/mod.rs b/idevice/src/usbmuxd/mod.rs index a32d317..c27c1b4 100644 --- a/idevice/src/usbmuxd/mod.rs +++ b/idevice/src/usbmuxd/mod.rs @@ -29,7 +29,7 @@ pub struct UsbmuxdConnection { tag: u32, } -#[derive()] +#[derive(Debug)] pub enum UsbmuxdAddr { UnixSocket(String), TcpSocket(SocketAddr),