mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 14:36:16 +01:00
Create new RSD service trait
This commit is contained in:
@@ -25,7 +25,7 @@ pub use services::*;
|
||||
pub use xpc::RemoteXpcClient;
|
||||
|
||||
use log::{debug, error, trace};
|
||||
use provider::IdeviceProvider;
|
||||
use provider::{IdeviceProvider, RsdProvider};
|
||||
use rustls::{crypto::CryptoProvider, pki_types::ServerName};
|
||||
use std::{
|
||||
io::{self, BufWriter},
|
||||
@@ -65,6 +65,25 @@ pub trait IdeviceService: Sized {
|
||||
) -> impl std::future::Future<Output = Result<Self, IdeviceError>> + Send;
|
||||
}
|
||||
|
||||
pub trait RsdService: Sized {
|
||||
fn rsd_service_name() -> &'static str;
|
||||
fn from_stream(
|
||||
stream: Self::Stream,
|
||||
) -> impl std::future::Future<Output = Result<Self, IdeviceError>> + Send;
|
||||
fn connect_rsd<'a, S>(
|
||||
provider: &'a mut impl RsdProvider<'a, Stream = S>,
|
||||
handshake: &mut rsd::RsdHandshake,
|
||||
) -> impl std::future::Future<Output = Result<Self, IdeviceError>>
|
||||
where
|
||||
Self: crate::RsdService<Stream = S>,
|
||||
S: ReadWrite,
|
||||
{
|
||||
handshake.connect(provider)
|
||||
}
|
||||
|
||||
type Stream: ReadWrite;
|
||||
}
|
||||
|
||||
/// Type alias for boxed device connection sockets
|
||||
///
|
||||
/// Used to enable dynamic dispatch of different connection types while maintaining
|
||||
@@ -424,6 +443,8 @@ pub enum IdeviceError {
|
||||
HeartbeatTimeout,
|
||||
#[error("not found")]
|
||||
NotFound,
|
||||
#[error("service not found")]
|
||||
ServiceNotFound,
|
||||
#[error("CDTunnel packet too short")]
|
||||
CdtunnelPacketTooShort,
|
||||
#[error("CDTunnel packet invalid magic")]
|
||||
|
||||
@@ -8,7 +8,7 @@ use std::{future::Future, pin::Pin};
|
||||
#[cfg(feature = "tcp")]
|
||||
use tokio::net::TcpStream;
|
||||
|
||||
use crate::{pairing_file::PairingFile, Idevice, IdeviceError};
|
||||
use crate::{pairing_file::PairingFile, Idevice, IdeviceError, ReadWrite};
|
||||
|
||||
#[cfg(feature = "usbmuxd")]
|
||||
use crate::usbmuxd::UsbmuxdAddr;
|
||||
@@ -42,6 +42,14 @@ pub trait IdeviceProvider: Unpin + Send + Sync + std::fmt::Debug {
|
||||
) -> Pin<Box<dyn Future<Output = Result<PairingFile, IdeviceError>> + Send>>;
|
||||
}
|
||||
|
||||
pub trait RsdProvider<'a>: Unpin + Send + Sync + std::fmt::Debug {
|
||||
fn connect_to_service_port(
|
||||
&'a mut self,
|
||||
port: u16,
|
||||
) -> impl std::future::Future<Output = Result<Self::Stream, IdeviceError>> + Send;
|
||||
type Stream: ReadWrite;
|
||||
}
|
||||
|
||||
/// TCP-based device connection provider
|
||||
#[cfg(feature = "tcp")]
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -8,10 +8,22 @@ use log::debug;
|
||||
use std::fmt::Write;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
use crate::{IdeviceError, ReadWrite};
|
||||
use crate::{IdeviceError, ReadWrite, RsdService};
|
||||
|
||||
/// The service name for the debug proxy as registered with lockdownd
|
||||
pub const SERVICE_NAME: &str = "com.apple.internal.dt.remote.debugproxy";
|
||||
impl<R: ReadWrite> RsdService for DebugProxyClient<R> {
|
||||
fn rsd_service_name() -> &'static str {
|
||||
"com.apple.internal.dt.remote.debugproxy"
|
||||
}
|
||||
|
||||
async fn from_stream(stream: R) -> Result<Self, IdeviceError> {
|
||||
Ok(Self {
|
||||
socket: stream,
|
||||
noack_mode: false,
|
||||
})
|
||||
}
|
||||
|
||||
type Stream = R;
|
||||
}
|
||||
|
||||
/// Client for interacting with the iOS debug proxy service
|
||||
///
|
||||
@@ -300,4 +312,3 @@ impl From<&str> for DebugserverCommand {
|
||||
s.to_string().into()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
// Jackson Coxson
|
||||
|
||||
use crate::{IdeviceError, ReadWrite, RsdService};
|
||||
|
||||
#[cfg(feature = "location_simulation")]
|
||||
pub mod location_simulation;
|
||||
pub mod message;
|
||||
pub mod process_control;
|
||||
pub mod remote_server;
|
||||
|
||||
pub const SERVICE_NAME: &str = "com.apple.instruments.dtservicehub";
|
||||
impl<R: ReadWrite> RsdService for remote_server::RemoteServerClient<R> {
|
||||
fn rsd_service_name() -> &'static str {
|
||||
"com.apple.instruments.dtservicehub"
|
||||
}
|
||||
|
||||
async fn from_stream(stream: R) -> Result<Self, IdeviceError> {
|
||||
Ok(Self::new(stream))
|
||||
}
|
||||
|
||||
type Stream = R;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::collections::HashMap;
|
||||
use log::warn;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{IdeviceError, ReadWrite, RemoteXpcClient};
|
||||
use crate::{provider::RsdProvider, IdeviceError, ReadWrite, RemoteXpcClient};
|
||||
|
||||
/// Describes an available XPC service
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@@ -23,21 +23,19 @@ pub struct RsdService {
|
||||
pub service_version: Option<i64>,
|
||||
}
|
||||
|
||||
pub struct RsdClient<R: ReadWrite> {
|
||||
inner: RemoteXpcClient<R>,
|
||||
pub struct RsdHandshake {
|
||||
pub services: HashMap<String, RsdService>,
|
||||
pub protocol_version: usize,
|
||||
pub properties: HashMap<String, plist::Value>,
|
||||
pub uuid: String,
|
||||
}
|
||||
|
||||
impl<R: ReadWrite> RsdClient<R> {
|
||||
pub async fn new(socket: R) -> Result<Self, IdeviceError> {
|
||||
Ok(Self {
|
||||
inner: RemoteXpcClient::new(socket).await?,
|
||||
})
|
||||
}
|
||||
impl RsdHandshake {
|
||||
pub async fn new(socket: impl ReadWrite) -> Result<Self, IdeviceError> {
|
||||
let mut xpc_client = RemoteXpcClient::new(socket).await?;
|
||||
let data = xpc_client.do_handshake().await?;
|
||||
|
||||
pub async fn get_services(&mut self) -> Result<HashMap<String, RsdService>, IdeviceError> {
|
||||
let data = self.inner.do_handshake().await?;
|
||||
|
||||
let data = match data
|
||||
let services_dict = match data
|
||||
.as_dictionary()
|
||||
.and_then(|x| x.get("Services"))
|
||||
.and_then(|x| x.as_dictionary())
|
||||
@@ -47,8 +45,8 @@ impl<R: ReadWrite> RsdClient<R> {
|
||||
};
|
||||
|
||||
// Parse available services
|
||||
let mut services = HashMap::new();
|
||||
for (name, service) in data.into_iter() {
|
||||
let mut services: HashMap<String, RsdService> = HashMap::new();
|
||||
for (name, service) in services_dict.into_iter() {
|
||||
match service.as_dictionary() {
|
||||
Some(service) => {
|
||||
let entitlement = match service.get("Entitlement").and_then(|x| x.as_string()) {
|
||||
@@ -116,6 +114,64 @@ impl<R: ReadWrite> RsdClient<R> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(services)
|
||||
let protocol_version = match data.as_dictionary().and_then(|x| {
|
||||
x.get("MessagingProtocolVersion")
|
||||
.and_then(|x| x.as_signed_integer())
|
||||
}) {
|
||||
Some(p) => p as usize,
|
||||
None => {
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
};
|
||||
|
||||
let uuid = match data
|
||||
.as_dictionary()
|
||||
.and_then(|x| x.get("UUID").and_then(|x| x.as_string()))
|
||||
{
|
||||
Some(u) => u.to_string(),
|
||||
None => {
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
};
|
||||
|
||||
let properties = match data
|
||||
.as_dictionary()
|
||||
.and_then(|x| x.get("Properties").and_then(|x| x.as_dictionary()))
|
||||
{
|
||||
Some(d) => d
|
||||
.into_iter()
|
||||
.map(|(name, prop)| (name.to_owned(), prop.to_owned()))
|
||||
.collect::<HashMap<String, plist::Value>>(),
|
||||
None => {
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
services,
|
||||
protocol_version,
|
||||
properties,
|
||||
uuid,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn connect<'a, T, S>(
|
||||
&mut self,
|
||||
provider: &'a mut impl RsdProvider<'a, Stream = S>,
|
||||
) -> Result<T, IdeviceError>
|
||||
where
|
||||
T: crate::RsdService<Stream = S>,
|
||||
S: ReadWrite,
|
||||
{
|
||||
let service_name = T::rsd_service_name();
|
||||
let service = match self.services.get(service_name) {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
return Err(IdeviceError::ServiceNotFound);
|
||||
}
|
||||
};
|
||||
|
||||
let stream = provider.connect_to_service_port(service.port).await?;
|
||||
T::from_stream(stream).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,11 @@ use std::{
|
||||
};
|
||||
|
||||
use log::debug;
|
||||
use stream::AdapterStream;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use crate::provider::RsdProvider;
|
||||
|
||||
pub mod adapter;
|
||||
pub mod packets;
|
||||
pub mod stream;
|
||||
@@ -36,6 +39,18 @@ pub(crate) fn log_packet(file: &Arc<tokio::sync::Mutex<tokio::fs::File>>, packet
|
||||
});
|
||||
}
|
||||
|
||||
impl<'a> RsdProvider<'a> for adapter::Adapter {
|
||||
async fn connect_to_service_port(
|
||||
&'a mut self,
|
||||
port: u16,
|
||||
) -> Result<stream::AdapterStream<'a>, crate::IdeviceError> {
|
||||
let s = stream::AdapterStream::connect(self, port).await?;
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
type Stream = AdapterStream<'a>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{
|
||||
|
||||
@@ -4,8 +4,8 @@ use std::io::Write;
|
||||
|
||||
use clap::{Arg, Command};
|
||||
use idevice::{
|
||||
core_device_proxy::CoreDeviceProxy, debug_proxy::DebugProxyClient, rsd::RsdClient,
|
||||
tcp::stream::AdapterStream, IdeviceService,
|
||||
core_device_proxy::CoreDeviceProxy, debug_proxy::DebugProxyClient, rsd::RsdHandshake,
|
||||
tcp::stream::AdapterStream, IdeviceService, RsdService,
|
||||
};
|
||||
|
||||
mod common;
|
||||
@@ -77,22 +77,12 @@ async fn main() {
|
||||
.expect("no RSD connect");
|
||||
|
||||
// Make the connection to RemoteXPC
|
||||
let mut client = RsdClient::new(stream).await.unwrap();
|
||||
let mut handshake = RsdHandshake::new(stream).await.unwrap();
|
||||
println!("{:?}", handshake.services);
|
||||
|
||||
// Get the debug proxy
|
||||
let service = client
|
||||
.get_services()
|
||||
let mut dp = DebugProxyClient::connect_rsd(&mut adapter, &mut handshake)
|
||||
.await
|
||||
.unwrap()
|
||||
.get(idevice::debug_proxy::SERVICE_NAME)
|
||||
.expect("Client did not contain debug proxy service")
|
||||
.to_owned();
|
||||
|
||||
let stream = AdapterStream::connect(&mut adapter, service.port)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut dp = DebugProxyClient::new(stream);
|
||||
.expect("no connect");
|
||||
|
||||
println!("Shell connected!");
|
||||
loop {
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
use clap::{Arg, Command};
|
||||
use idevice::{
|
||||
core_device_proxy::CoreDeviceProxy, rsd::RsdClient, tcp::stream::AdapterStream, IdeviceService,
|
||||
core_device_proxy::CoreDeviceProxy, rsd::RsdHandshake, tcp::stream::AdapterStream,
|
||||
IdeviceService, RsdService,
|
||||
};
|
||||
|
||||
mod common;
|
||||
@@ -76,22 +77,12 @@ async fn main() {
|
||||
.expect("no RSD connect");
|
||||
|
||||
// Make the connection to RemoteXPC
|
||||
let mut client = RsdClient::new(stream).await.unwrap();
|
||||
let mut handshake = RsdHandshake::new(stream).await.unwrap();
|
||||
|
||||
// Get the debug proxy
|
||||
let service = client
|
||||
.get_services()
|
||||
.await
|
||||
.unwrap()
|
||||
.get(idevice::dvt::SERVICE_NAME)
|
||||
.expect("Client did not contain DVT service")
|
||||
.to_owned();
|
||||
|
||||
let stream = AdapterStream::connect(&mut adapter, service.port)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut ls_client = idevice::dvt::remote_server::RemoteServerClient::new(stream);
|
||||
let mut ls_client =
|
||||
idevice::dvt::remote_server::RemoteServerClient::connect_rsd(&mut adapter, &mut handshake)
|
||||
.await
|
||||
.expect("Failed to connect");
|
||||
ls_client.read_message(0).await.expect("no read??");
|
||||
|
||||
let mut ls_client =
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
use clap::{Arg, Command};
|
||||
use idevice::{
|
||||
core_device_proxy::CoreDeviceProxy, rsd::RsdClient, tcp::stream::AdapterStream, IdeviceService,
|
||||
core_device_proxy::CoreDeviceProxy, rsd::RsdHandshake, tcp::stream::AdapterStream,
|
||||
IdeviceService, RsdService,
|
||||
};
|
||||
|
||||
mod common;
|
||||
@@ -84,22 +85,12 @@ async fn main() {
|
||||
.expect("no RSD connect");
|
||||
|
||||
// Make the connection to RemoteXPC
|
||||
let mut client = RsdClient::new(stream).await.unwrap();
|
||||
let mut handshake = RsdHandshake::new(stream).await.unwrap();
|
||||
|
||||
// Get the debug proxy
|
||||
let service = client
|
||||
.get_services()
|
||||
.await
|
||||
.unwrap()
|
||||
.get(idevice::dvt::SERVICE_NAME)
|
||||
.expect("Client did not contain DVT service")
|
||||
.to_owned();
|
||||
|
||||
let stream = AdapterStream::connect(&mut adapter, service.port)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut rs_client = idevice::dvt::remote_server::RemoteServerClient::new(stream);
|
||||
let mut rs_client =
|
||||
idevice::dvt::remote_server::RemoteServerClient::connect_rsd(&mut adapter, &mut handshake)
|
||||
.await
|
||||
.expect("no connect");
|
||||
rs_client.read_message(0).await.expect("no read??");
|
||||
let mut pc_client = idevice::dvt::process_control::ProcessControlClient::new(&mut rs_client)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user