mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 14:36:16 +01:00
Implement the service trait
This commit is contained in:
@@ -1,14 +1,11 @@
|
|||||||
// Jackson Coxson
|
// Jackson Coxson
|
||||||
|
|
||||||
use crate::{Idevice, IdeviceError};
|
use crate::{lockdownd::LockdowndClient, Idevice, IdeviceError, IdeviceService};
|
||||||
|
|
||||||
use byteorder::{BigEndian, WriteBytesExt};
|
use byteorder::{BigEndian, WriteBytesExt};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
|
||||||
pub const SERVCE_NAME: &str = "com.apple.internal.devicecompute.CoreDeviceProxy";
|
|
||||||
const DEFAULT_MTU: u32 = 16000;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct CDTunnelPacket {
|
pub struct CDTunnelPacket {
|
||||||
body: Vec<u8>,
|
body: Vec<u8>,
|
||||||
@@ -67,6 +64,28 @@ pub struct CoreDeviceProxy {
|
|||||||
pub mtu: u32,
|
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<Self, IdeviceError> {
|
||||||
|
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)]
|
#[derive(Serialize)]
|
||||||
struct HandshakeRequest {
|
struct HandshakeRequest {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
@@ -94,17 +113,19 @@ pub struct HandshakeResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CoreDeviceProxy {
|
impl CoreDeviceProxy {
|
||||||
|
const DEFAULT_MTU: u32 = 16000;
|
||||||
|
|
||||||
pub fn new(idevice: Idevice) -> Self {
|
pub fn new(idevice: Idevice) -> Self {
|
||||||
Self {
|
Self {
|
||||||
idevice,
|
idevice,
|
||||||
mtu: DEFAULT_MTU,
|
mtu: Self::DEFAULT_MTU,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn establish_tunnel(&mut self) -> Result<HandshakeResponse, IdeviceError> {
|
pub async fn establish_tunnel(&mut self) -> Result<HandshakeResponse, IdeviceError> {
|
||||||
let req = HandshakeRequest {
|
let req = HandshakeRequest {
|
||||||
packet_type: "clientHandshakeRequest".to_string(),
|
packet_type: "clientHandshakeRequest".to_string(),
|
||||||
mtu: DEFAULT_MTU,
|
mtu: Self::DEFAULT_MTU,
|
||||||
};
|
};
|
||||||
|
|
||||||
let req = CDTunnelPacket::serialize(&CDTunnelPacket {
|
let req = CDTunnelPacket::serialize(&CDTunnelPacket {
|
||||||
|
|||||||
@@ -1,12 +1,34 @@
|
|||||||
// Jackson Coxson
|
// Jackson Coxson
|
||||||
// Abstractions for the heartbeat service on iOS
|
// Abstractions for the heartbeat service on iOS
|
||||||
|
|
||||||
use crate::{Idevice, IdeviceError};
|
use crate::{lockdownd::LockdowndClient, Idevice, IdeviceError, IdeviceService};
|
||||||
|
|
||||||
pub struct HeartbeatClient {
|
pub struct HeartbeatClient {
|
||||||
pub idevice: Idevice,
|
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<Self, IdeviceError> {
|
||||||
|
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 {
|
impl HeartbeatClient {
|
||||||
pub fn new(idevice: Idevice) -> Self {
|
pub fn new(idevice: Idevice) -> Self {
|
||||||
Self { idevice }
|
Self { idevice }
|
||||||
|
|||||||
@@ -3,12 +3,34 @@
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{Idevice, IdeviceError};
|
use crate::{lockdownd::LockdowndClient, Idevice, IdeviceError, IdeviceService};
|
||||||
|
|
||||||
pub struct InstallationProxyClient {
|
pub struct InstallationProxyClient {
|
||||||
pub idevice: Idevice,
|
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<Self, IdeviceError> {
|
||||||
|
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 {
|
impl InstallationProxyClient {
|
||||||
pub fn new(idevice: Idevice) -> Self {
|
pub fn new(idevice: Idevice) -> Self {
|
||||||
Self { idevice }
|
Self { idevice }
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ pub mod xpc;
|
|||||||
|
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
|
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
|
||||||
|
use provider::IdeviceProvider;
|
||||||
use std::io::{self, BufWriter};
|
use std::io::{self, BufWriter};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
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 {}
|
pub trait ReadWrite: AsyncRead + AsyncWrite + Unpin + Send + Sync + std::fmt::Debug {}
|
||||||
impl<T: AsyncRead + AsyncWrite + Unpin + Send + Sync + std::fmt::Debug> ReadWrite for T {}
|
impl<T: AsyncRead + AsyncWrite + Unpin + Send + Sync + std::fmt::Debug> ReadWrite for T {}
|
||||||
|
|
||||||
|
pub trait IdeviceService: Sized {
|
||||||
|
fn service_name() -> &'static str;
|
||||||
|
fn connect(
|
||||||
|
provider: &impl IdeviceProvider,
|
||||||
|
) -> impl std::future::Future<Output = Result<Self, IdeviceError>> + Send;
|
||||||
|
}
|
||||||
|
|
||||||
pub type IdeviceSocket = Box<dyn ReadWrite>;
|
pub type IdeviceSocket = Box<dyn ReadWrite>;
|
||||||
|
|
||||||
pub struct Idevice {
|
pub struct Idevice {
|
||||||
|
|||||||
@@ -1,17 +1,28 @@
|
|||||||
// Jackson Coxson
|
// Jackson Coxson
|
||||||
// Abstractions for lockdownd
|
// Abstractions for lockdownd
|
||||||
|
|
||||||
pub const LOCKDOWND_PORT: u16 = 62078;
|
|
||||||
|
|
||||||
use log::error;
|
use log::error;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{pairing_file, Idevice, IdeviceError};
|
use crate::{pairing_file, Idevice, IdeviceError, IdeviceService};
|
||||||
|
|
||||||
pub struct LockdowndClient {
|
pub struct LockdowndClient {
|
||||||
pub idevice: crate::Idevice,
|
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<Self, IdeviceError> {
|
||||||
|
let idevice = provider.connect(Self::LOCKDOWND_PORT).await?;
|
||||||
|
Ok(Self { idevice })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
struct LockdowndRequest {
|
struct LockdowndRequest {
|
||||||
@@ -21,6 +32,8 @@ struct LockdowndRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LockdowndClient {
|
impl LockdowndClient {
|
||||||
|
pub const LOCKDOWND_PORT: u16 = 62078;
|
||||||
|
|
||||||
pub fn new(idevice: Idevice) -> Self {
|
pub fn new(idevice: Idevice) -> Self {
|
||||||
Self { idevice }
|
Self { idevice }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,33 @@
|
|||||||
// Jackson Coxson
|
// Jackson Coxson
|
||||||
|
|
||||||
use crate::{Idevice, IdeviceError};
|
use crate::{lockdownd::LockdowndClient, Idevice, IdeviceError, IdeviceService};
|
||||||
|
|
||||||
pub struct ImageMounter {
|
pub struct ImageMounter {
|
||||||
idevice: Idevice,
|
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<Self, IdeviceError> {
|
||||||
|
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 {
|
impl ImageMounter {
|
||||||
pub fn new(idevice: Idevice) -> Self {
|
pub fn new(idevice: Idevice) -> Self {
|
||||||
Self { idevice }
|
Self { idevice }
|
||||||
|
|||||||
@@ -4,19 +4,24 @@ use std::net::{IpAddr, SocketAddr};
|
|||||||
|
|
||||||
use tokio::net::TcpStream;
|
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
|
// 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(
|
fn connect(
|
||||||
&self,
|
&self,
|
||||||
port: u16,
|
port: u16,
|
||||||
) -> impl std::future::Future<Output = Result<Idevice, IdeviceError>> + Send;
|
) -> impl std::future::Future<Output = Result<Idevice, IdeviceError>> + Send;
|
||||||
fn label(&self) -> &str;
|
fn label(&self) -> &str;
|
||||||
|
fn get_pairing_file(
|
||||||
|
&self,
|
||||||
|
) -> impl std::future::Future<Output = Result<PairingFile, IdeviceError>> + Send;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct TcpProvider {
|
pub struct TcpProvider {
|
||||||
addr: IpAddr,
|
addr: IpAddr,
|
||||||
|
pairing_file: PairingFile,
|
||||||
label: String,
|
label: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,12 +34,18 @@ impl IdeviceProvider for TcpProvider {
|
|||||||
fn label(&self) -> &str {
|
fn label(&self) -> &str {
|
||||||
self.label.as_str()
|
self.label.as_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_pairing_file(&self) -> Result<PairingFile, IdeviceError> {
|
||||||
|
Ok(self.pairing_file.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "usbmuxd")]
|
#[cfg(feature = "usbmuxd")]
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct UsbmuxdProvider {
|
pub struct UsbmuxdProvider {
|
||||||
addr: UsbmuxdAddr,
|
addr: UsbmuxdAddr,
|
||||||
tag: u32,
|
tag: u32,
|
||||||
|
udid: String,
|
||||||
device_id: u32,
|
device_id: u32,
|
||||||
label: String,
|
label: String,
|
||||||
}
|
}
|
||||||
@@ -51,4 +62,9 @@ impl IdeviceProvider for UsbmuxdProvider {
|
|||||||
fn label(&self) -> &str {
|
fn label(&self) -> &str {
|
||||||
self.label.as_str()
|
self.label.as_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_pairing_file(&self) -> Result<PairingFile, IdeviceError> {
|
||||||
|
let mut usbmuxd = self.addr.connect(self.tag).await?;
|
||||||
|
usbmuxd.get_pair_record(&self.udid).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ pub struct UsbmuxdConnection {
|
|||||||
tag: u32,
|
tag: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive()]
|
#[derive(Debug)]
|
||||||
pub enum UsbmuxdAddr {
|
pub enum UsbmuxdAddr {
|
||||||
UnixSocket(String),
|
UnixSocket(String),
|
||||||
TcpSocket(SocketAddr),
|
TcpSocket(SocketAddr),
|
||||||
|
|||||||
Reference in New Issue
Block a user