mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 14:36:16 +01:00
Use smoltcp as a software TUN manager (broken)
This commit is contained in:
184
Cargo.lock
generated
184
Cargo.lock
generated
@@ -138,6 +138,12 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.8.0"
|
||||
@@ -178,6 +184,15 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder_slice"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b294e30387378958e8bf8f4242131b930ea615ff81e8cac2440cea0a6013190"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.9.0"
|
||||
@@ -365,6 +380,38 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86f6162c53f659f65d00619fe31f14556a6e9f8752ccc4a41bd177ffcf3d6130"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"defmt-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-macros"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d135dd939bad62d7490b0002602d35b358dce5fd9233a709d3c1ef467d4bde6"
|
||||
dependencies = [
|
||||
"defmt-parser",
|
||||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-parser"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3983b127f13995e68c1e29071e5d115cd96f215ccb5e6812e3728cd6f92653b3"
|
||||
dependencies = [
|
||||
"thiserror 2.0.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
@@ -374,6 +421,17 @@ dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive-into-owned"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c9d94d81e3819a7b06a8638f448bc6339371ca9b6076a99d4a43eece3c4c923"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@@ -590,7 +648,7 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ba121d81ab5ea05b0cd5858516266800bf965531a794f7ac58e3eeb804f364f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.8.0",
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
@@ -643,12 +701,31 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||
dependencies = [
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@@ -904,12 +981,14 @@ dependencies = [
|
||||
"log",
|
||||
"ns-keyed-archive",
|
||||
"openssl",
|
||||
"pcap-file",
|
||||
"plist",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"thiserror",
|
||||
"smoltcp",
|
||||
"thiserror 2.0.11",
|
||||
"tokio",
|
||||
"tokio-openssl",
|
||||
"uuid",
|
||||
@@ -1057,6 +1136,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "managed"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
@@ -1121,7 +1206,7 @@ version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.8.0",
|
||||
"cfg-if",
|
||||
"cfg_aliases 0.1.1",
|
||||
"libc",
|
||||
@@ -1134,7 +1219,7 @@ version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.8.0",
|
||||
"cfg-if",
|
||||
"cfg_aliases 0.2.1",
|
||||
"libc",
|
||||
@@ -1158,7 +1243,7 @@ checksum = "f237a10fe003123daa55a74b63a0b0a65de1671b2d128711ffe5886891a8f77f"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"plist",
|
||||
"thiserror",
|
||||
"thiserror 2.0.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1188,7 +1273,7 @@ version = "0.10.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.8.0",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
@@ -1265,6 +1350,17 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pcap-file"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc1f139757b058f9f37b76c48501799d12c9aa0aa4c0d4c980b062ee925d1b2"
|
||||
dependencies = [
|
||||
"byteorder_slice",
|
||||
"derive-into-owned",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
@@ -1319,6 +1415,28 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
@@ -1352,7 +1470,7 @@ version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1455,7 +1573,7 @@ version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.8.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
@@ -1536,7 +1654,7 @@ version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.8.0",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@@ -1638,6 +1756,22 @@ version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "smoltcp"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"byteorder",
|
||||
"cfg-if",
|
||||
"defmt",
|
||||
"heapless",
|
||||
"libc",
|
||||
"log",
|
||||
"managed",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.8"
|
||||
@@ -1720,7 +1854,7 @@ version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.8.0",
|
||||
"core-foundation",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
@@ -1749,13 +1883,33 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 2.0.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1941,7 +2095,7 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53141e64197ff7e758b8152615e50bb4a3b18c970738876e7906d31f242c7d6e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.8.0",
|
||||
"blocking",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
@@ -1956,7 +2110,7 @@ dependencies = [
|
||||
"mac_address",
|
||||
"nix 0.29.0",
|
||||
"scopeguard",
|
||||
"thiserror",
|
||||
"thiserror 2.0.11",
|
||||
"tokio",
|
||||
"windows-sys 0.59.0",
|
||||
"winreg",
|
||||
@@ -2406,7 +2560,7 @@ dependencies = [
|
||||
"c2rust-bitfields",
|
||||
"libloading",
|
||||
"log",
|
||||
"thiserror",
|
||||
"thiserror 2.0.11",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@@ -2416,7 +2570,7 @@ version = "0.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 2.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -32,13 +32,14 @@ json = { version = "0.12", optional = true }
|
||||
byteorder = { version = "1.5", optional = true }
|
||||
|
||||
reqwest = { version = "0.12", features = ["json"], optional = true }
|
||||
smoltcp = { version = "0.12", optional = true }
|
||||
pcap-file = { version = "2.0", optional = true }
|
||||
|
||||
sha2 = { version = "0.10", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.43", features = ["fs"] }
|
||||
|
||||
|
||||
[features]
|
||||
core_device_proxy = ["dep:serde_json", "dep:json", "dep:byteorder"]
|
||||
debug_proxy = []
|
||||
@@ -47,10 +48,11 @@ heartbeat = []
|
||||
installation_proxy = []
|
||||
misagent = []
|
||||
mounter = ["dep:sha2"]
|
||||
usbmuxd = ["tokio/net"]
|
||||
tcp = ["tokio/net"]
|
||||
tunnel_tcp_stack = ["dep:smoltcp", "tokio/sync", "dep:pcap-file"]
|
||||
tss = ["dep:uuid", "dep:reqwest"]
|
||||
tunneld = ["dep:serde_json", "dep:json", "dep:reqwest"]
|
||||
usbmuxd = ["tokio/net"]
|
||||
xpc = [
|
||||
"tokio/sync",
|
||||
"dep:indexmap",
|
||||
@@ -70,6 +72,7 @@ full = [
|
||||
"usbmuxd",
|
||||
"xpc",
|
||||
"tcp",
|
||||
"tunnel_tcp_stack",
|
||||
"tss",
|
||||
"tunneld",
|
||||
]
|
||||
|
||||
141
idevice/src/core_device_proxy/device.rs
Normal file
141
idevice/src/core_device_proxy/device.rs
Normal file
@@ -0,0 +1,141 @@
|
||||
// Jackson Coxson
|
||||
|
||||
use log::{debug, warn};
|
||||
use pcap_file::pcapng::PcapNgWriter;
|
||||
use smoltcp::{
|
||||
phy::{self, Device, DeviceCapabilities, Medium},
|
||||
time::Instant,
|
||||
};
|
||||
use tokio::sync::{
|
||||
mpsc::{error::TryRecvError, unbounded_channel, UnboundedReceiver, UnboundedSender},
|
||||
oneshot::{channel, Sender},
|
||||
};
|
||||
|
||||
use crate::IdeviceError;
|
||||
|
||||
use super::CoreDeviceProxy;
|
||||
|
||||
pub struct ProxyDevice {
|
||||
sender: UnboundedSender<(Vec<u8>, Sender<Option<IdeviceError>>)>,
|
||||
receiver: UnboundedReceiver<Result<Vec<u8>, IdeviceError>>,
|
||||
mtu: usize,
|
||||
}
|
||||
|
||||
impl ProxyDevice {
|
||||
pub fn new(mut proxy: CoreDeviceProxy) -> Self {
|
||||
let (sender, mut stack_recv) = unbounded_channel();
|
||||
let (stack_send, receiver) = unbounded_channel();
|
||||
let mtu = proxy.mtu as usize;
|
||||
|
||||
tokio::task::spawn(async move {
|
||||
loop {
|
||||
tokio::select! {
|
||||
res = proxy.recv() => {
|
||||
// debug!("stack recv: {res:02X?}");
|
||||
if stack_send.send(res).is_err() {
|
||||
warn!("Interface failed to recv");
|
||||
break;
|
||||
}
|
||||
}
|
||||
pkt = stack_recv.recv() => {
|
||||
let pkt: (Vec<u8>, Sender<Option<IdeviceError>>) = match pkt {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
warn!("Interface sender closed");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// debug!("stack send: {:02X?}", pkt.0);
|
||||
pkt.1.send(proxy.send(&pkt.0).await.err()).ok();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Self {
|
||||
sender,
|
||||
receiver,
|
||||
mtu,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for ProxyDevice {
|
||||
type RxToken<'a> = RxToken;
|
||||
type TxToken<'a> = TxToken;
|
||||
|
||||
fn capabilities(&self) -> DeviceCapabilities {
|
||||
let mut caps = DeviceCapabilities::default();
|
||||
caps.medium = Medium::Ip;
|
||||
caps.max_transmission_unit = self.mtu;
|
||||
caps
|
||||
}
|
||||
|
||||
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||
match self.receiver.try_recv() {
|
||||
Ok(Ok(buffer)) => {
|
||||
let rx = RxToken { buffer };
|
||||
let tx = TxToken {
|
||||
sender: self.sender.clone(),
|
||||
};
|
||||
Some((rx, tx))
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
warn!("Failed to recv message: {e:?}");
|
||||
None
|
||||
}
|
||||
Err(TryRecvError::Disconnected) => {
|
||||
warn!("Proxy sender is closed");
|
||||
None
|
||||
}
|
||||
Err(TryRecvError::Empty) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
|
||||
Some(TxToken {
|
||||
sender: self.sender.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct RxToken {
|
||||
buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl phy::RxToken for RxToken {
|
||||
fn consume<R, F>(self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&[u8]) -> R,
|
||||
{
|
||||
f(&self.buffer[..])
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct TxToken {
|
||||
sender: UnboundedSender<(Vec<u8>, Sender<Option<IdeviceError>>)>,
|
||||
}
|
||||
|
||||
impl phy::TxToken for TxToken {
|
||||
fn consume<R, F>(self, len: usize, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> R,
|
||||
{
|
||||
let mut buffer = vec![0; len];
|
||||
let result = f(&mut buffer);
|
||||
let (tx, rx) = channel();
|
||||
match self.sender.send((buffer, tx)) {
|
||||
Ok(_) => {
|
||||
if let Err(e) = rx.blocking_recv() {
|
||||
warn!("Failed to send to idevice: {e:?}");
|
||||
}
|
||||
}
|
||||
Err(err) => warn!("Failed to send: {}", err),
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
277
idevice/src/core_device_proxy/interface.rs
Normal file
277
idevice/src/core_device_proxy/interface.rs
Normal file
@@ -0,0 +1,277 @@
|
||||
// Jackson Coxson
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
io::ErrorKind,
|
||||
net::{IpAddr, Ipv6Addr},
|
||||
pin::Pin,
|
||||
str::FromStr,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use log::{debug, warn};
|
||||
use smoltcp::{
|
||||
iface::{Config, Interface, SocketHandle, SocketSet},
|
||||
socket::tcp,
|
||||
time::Instant,
|
||||
wire::{IpAddress, IpCidr},
|
||||
};
|
||||
use tokio::{
|
||||
io::{self, AsyncRead, AsyncWrite},
|
||||
sync::mpsc::{error::TryRecvError, unbounded_channel, UnboundedReceiver, UnboundedSender},
|
||||
};
|
||||
|
||||
use crate::IdeviceError;
|
||||
|
||||
const TCP_BUFFER_SIZE: usize = 1024 * 1024;
|
||||
|
||||
pub struct TunnelInterface {
|
||||
thread_sender: UnboundedSender<ThreadMessage>,
|
||||
}
|
||||
|
||||
enum ThreadMessage {
|
||||
NewTcp((u16, UnboundedSender<Vec<u8>>, UnboundedReceiver<Vec<u8>>)),
|
||||
// left for possible UDP/other in the future??
|
||||
}
|
||||
|
||||
struct TunnelSocketHandle {
|
||||
handle: SocketHandle,
|
||||
sender: UnboundedSender<Vec<u8>>,
|
||||
receiver: UnboundedReceiver<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Channel {
|
||||
sender: UnboundedSender<Vec<u8>>,
|
||||
receiver: UnboundedReceiver<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl TunnelInterface {
|
||||
pub fn new(proxy: super::CoreDeviceProxy) -> Result<Self, IdeviceError> {
|
||||
let ip: IpAddr = match IpAddr::from_str(&proxy.handshake.client_parameters.address) {
|
||||
Ok(i) => i,
|
||||
Err(e) => {
|
||||
warn!("Failed to parse IP as IP address: {e:?}");
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
};
|
||||
let device_ip: Ipv6Addr = match proxy.handshake.server_address.parse() {
|
||||
Ok(d) => d,
|
||||
Err(_) => {
|
||||
warn!("Device IP isn't parsable as IPv6");
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
};
|
||||
let mut device = super::device::ProxyDevice::new(proxy);
|
||||
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
|
||||
|
||||
// Create the interface
|
||||
let mut interface = Interface::new(config, &mut device, smoltcp::time::Instant::now());
|
||||
|
||||
// Add the IPv6 address to the interface
|
||||
let ip = match ip {
|
||||
IpAddr::V4(_) => {
|
||||
warn!("IP was IPv4, not 6");
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
IpAddr::V6(ipv6_addr) => ipv6_addr,
|
||||
};
|
||||
interface.update_ip_addrs(|addrs| {
|
||||
// Add the IPv6 address with a prefix length (e.g., 64 for typical IPv6 subnets)
|
||||
addrs.push(IpCidr::new(IpAddress::Ipv6(ip), 64)).unwrap();
|
||||
});
|
||||
|
||||
let (thread_sender, mut thread_rx) = unbounded_channel();
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
// based on https://github.com/smoltcp-rs/smoltcp/blob/main/examples/client.rs
|
||||
let mut sockets = SocketSet::new(vec![]);
|
||||
let mut handles: HashMap<u16, TunnelSocketHandle> = HashMap::new();
|
||||
let mut last_port = 1024; // host to bind and index by
|
||||
loop {
|
||||
let timestamp = Instant::now();
|
||||
interface.poll(timestamp, &mut device, &mut sockets);
|
||||
|
||||
let mut to_remove = Vec::new();
|
||||
let keys: Vec<u16> = handles.keys().cloned().collect();
|
||||
|
||||
for key in keys {
|
||||
if let Some(handle) = handles.get_mut(&key) {
|
||||
let socket = sockets.get_mut::<tcp::Socket>(handle.handle);
|
||||
|
||||
if socket.may_recv() {
|
||||
if let Err(e) = socket.recv(|data| {
|
||||
if !data.is_empty() && handle.sender.send(data.to_owned()).is_err()
|
||||
{
|
||||
warn!("Handle dropped");
|
||||
to_remove.push(key);
|
||||
}
|
||||
(data.len(), data)
|
||||
}) {
|
||||
warn!("Disconnected from socket: {e:?}");
|
||||
to_remove.push(key);
|
||||
}
|
||||
if socket.can_send() {
|
||||
match handle.receiver.try_recv() {
|
||||
Ok(data) => {
|
||||
let queued = socket.send_slice(&data[..]).unwrap();
|
||||
if queued < data.len() {
|
||||
log::error!("Failed to queue packet for send");
|
||||
}
|
||||
}
|
||||
Err(TryRecvError::Empty) => {} // wait
|
||||
Err(TryRecvError::Disconnected) => {
|
||||
debug!("handle is dropped");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("Can't send!!");
|
||||
}
|
||||
} else if socket.may_send() {
|
||||
debug!("close");
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the requested threads
|
||||
for t in to_remove {
|
||||
if let Some(h) = handles.remove(&t) {
|
||||
sockets.remove(h.handle);
|
||||
// When the struct is dropped, the unbounded_channel will close.
|
||||
// Because the channel is closed, the next time recv or send is called will
|
||||
// error.
|
||||
}
|
||||
}
|
||||
|
||||
match thread_rx.try_recv() {
|
||||
Ok(msg) => match msg {
|
||||
ThreadMessage::NewTcp((port, tx, rx)) => {
|
||||
// Create sockets
|
||||
let tcp_rx_buffer = tcp::SocketBuffer::new(vec![0; TCP_BUFFER_SIZE]);
|
||||
let tcp_tx_buffer = tcp::SocketBuffer::new(vec![0; TCP_BUFFER_SIZE]);
|
||||
let tcp_socket = tcp::Socket::new(tcp_rx_buffer, tcp_tx_buffer);
|
||||
let handle = sockets.add(tcp_socket);
|
||||
let socket = sockets.get_mut::<tcp::Socket>(handle);
|
||||
socket
|
||||
.connect(interface.context(), (device_ip, port), last_port)
|
||||
.unwrap();
|
||||
handles.insert(
|
||||
last_port,
|
||||
TunnelSocketHandle {
|
||||
handle,
|
||||
sender: tx,
|
||||
receiver: rx,
|
||||
},
|
||||
);
|
||||
|
||||
last_port += 1;
|
||||
}
|
||||
},
|
||||
Err(TryRecvError::Disconnected) => {
|
||||
debug!("Thread sender dropped");
|
||||
break;
|
||||
}
|
||||
Err(TryRecvError::Empty) => {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
let poll_delay = interface
|
||||
.poll_delay(timestamp, &sockets)
|
||||
.unwrap_or(smoltcp::time::Duration::from_millis(100))
|
||||
.millis();
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(poll_delay));
|
||||
}
|
||||
});
|
||||
|
||||
Ok(Self { thread_sender })
|
||||
}
|
||||
|
||||
pub fn connect_tcp(&mut self, port: u16) -> Result<Channel, IdeviceError> {
|
||||
let (tx, rx) = unbounded_channel();
|
||||
let (rtx, rrx) = unbounded_channel();
|
||||
if self
|
||||
.thread_sender
|
||||
.send(ThreadMessage::NewTcp((port, rtx, rx)))
|
||||
.is_err()
|
||||
{
|
||||
return Err(IdeviceError::TunnelThreadClosed);
|
||||
}
|
||||
|
||||
Ok(Channel {
|
||||
sender: tx,
|
||||
receiver: rrx,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
pub async fn send(&self, data: Vec<u8>) -> Result<(), IdeviceError> {
|
||||
if let Err(e) = self.sender.send(data) {
|
||||
warn!("Failed to send: {e:?}");
|
||||
return Err(IdeviceError::ChannelClosed);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn recv(&mut self) -> Result<Vec<u8>, IdeviceError> {
|
||||
match self.receiver.recv().await {
|
||||
Some(d) => Ok(d),
|
||||
None => {
|
||||
warn!("Failed to recv");
|
||||
Err(IdeviceError::ChannelClosed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncRead for Channel {
|
||||
fn poll_read(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
buf: &mut tokio::io::ReadBuf<'_>,
|
||||
) -> Poll<io::Result<()>> {
|
||||
match Pin::new(&mut self.receiver).poll_recv(cx) {
|
||||
Poll::Ready(Some(data)) => {
|
||||
let len = data.len().min(buf.remaining());
|
||||
buf.put_slice(&data[..len]);
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
Poll::Ready(None) => {
|
||||
warn!("unexpected eof");
|
||||
Poll::Ready(Err(io::Error::new(
|
||||
ErrorKind::UnexpectedEof,
|
||||
"Channel closed",
|
||||
)))
|
||||
}
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncWrite for Channel {
|
||||
fn poll_write(
|
||||
self: Pin<&mut Self>,
|
||||
_cx: &mut Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> Poll<io::Result<usize>> {
|
||||
let data = buf.to_vec();
|
||||
match self.sender.send(data) {
|
||||
Ok(_) => Poll::Ready(Ok(buf.len())),
|
||||
Err(e) => {
|
||||
warn!("Failed to send data: {e:?}");
|
||||
Poll::Ready(Err(io::Error::new(ErrorKind::BrokenPipe, "Channel closed")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
// Jackson Coxson
|
||||
|
||||
#[cfg(feature = "tunnel_tcp_stack")]
|
||||
mod device;
|
||||
#[cfg(feature = "tunnel_tcp_stack")]
|
||||
mod interface;
|
||||
|
||||
use crate::{lockdownd::LockdowndClient, Idevice, IdeviceError, IdeviceService};
|
||||
|
||||
use byteorder::{BigEndian, WriteBytesExt};
|
||||
@@ -61,6 +66,7 @@ impl CDTunnelPacket {
|
||||
|
||||
pub struct CoreDeviceProxy {
|
||||
pub idevice: Idevice,
|
||||
pub handshake: HandshakeResponse,
|
||||
pub mtu: u32,
|
||||
}
|
||||
|
||||
@@ -86,7 +92,7 @@ impl IdeviceService for CoreDeviceProxy {
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(Self::new(idevice))
|
||||
Self::new(idevice).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,14 +125,7 @@ pub struct HandshakeResponse {
|
||||
impl CoreDeviceProxy {
|
||||
const DEFAULT_MTU: u32 = 16000;
|
||||
|
||||
pub fn new(idevice: Idevice) -> Self {
|
||||
Self {
|
||||
idevice,
|
||||
mtu: Self::DEFAULT_MTU,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn establish_tunnel(&mut self) -> Result<HandshakeResponse, IdeviceError> {
|
||||
pub async fn new(mut idevice: Idevice) -> Result<Self, IdeviceError> {
|
||||
let req = HandshakeRequest {
|
||||
packet_type: "clientHandshakeRequest".to_string(),
|
||||
mtu: Self::DEFAULT_MTU,
|
||||
@@ -136,11 +135,8 @@ impl CoreDeviceProxy {
|
||||
body: serde_json::to_vec(&req)?,
|
||||
})?;
|
||||
|
||||
self.idevice.send_raw(&req).await?;
|
||||
let recv = self
|
||||
.idevice
|
||||
.read_raw(CDTunnelPacket::MAGIC.len() + 2)
|
||||
.await?;
|
||||
idevice.send_raw(&req).await?;
|
||||
let recv = idevice.read_raw(CDTunnelPacket::MAGIC.len() + 2).await?;
|
||||
|
||||
if recv.len() < CDTunnelPacket::MAGIC.len() + 2 {
|
||||
return Err(IdeviceError::CdtunnelPacketTooShort);
|
||||
@@ -151,10 +147,14 @@ impl CoreDeviceProxy {
|
||||
recv[CDTunnelPacket::MAGIC.len() + 1],
|
||||
]) as usize;
|
||||
|
||||
let recv = self.idevice.read_raw(len).await?;
|
||||
let recv = idevice.read_raw(len).await?;
|
||||
let res = serde_json::from_slice::<HandshakeResponse>(&recv)?;
|
||||
|
||||
Ok(res)
|
||||
Ok(Self {
|
||||
idevice,
|
||||
handshake: res,
|
||||
mtu: Self::DEFAULT_MTU,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send(&mut self, data: &[u8]) -> Result<(), IdeviceError> {
|
||||
@@ -165,4 +165,9 @@ impl CoreDeviceProxy {
|
||||
pub async fn recv(&mut self) -> Result<Vec<u8>, IdeviceError> {
|
||||
self.idevice.read_any(self.mtu).await
|
||||
}
|
||||
|
||||
#[cfg(feature = "tunnel_tcp_stack")]
|
||||
pub fn create_software_tunnel(self) -> Result<interface::TunnelInterface, IdeviceError> {
|
||||
interface::TunnelInterface::new(self)
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ mod util;
|
||||
#[cfg(feature = "xpc")]
|
||||
pub mod xpc;
|
||||
|
||||
use log::{debug, error};
|
||||
use log::{debug, error, trace};
|
||||
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
|
||||
use provider::IdeviceProvider;
|
||||
use std::io::{self, BufWriter};
|
||||
@@ -144,7 +144,7 @@ impl Idevice {
|
||||
let part_len = message_parts.len() - 1;
|
||||
|
||||
for (i, part) in message_parts.enumerate() {
|
||||
debug!("Writing {i}/{part_len}");
|
||||
trace!("Writing {i}/{part_len}");
|
||||
socket.write_all(part).await?;
|
||||
callback(((i, part_len), state.clone())).await;
|
||||
}
|
||||
@@ -231,6 +231,7 @@ impl Idevice {
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum IdeviceError {
|
||||
#[error("device socket io failed")]
|
||||
Socket(#[from] io::Error),
|
||||
@@ -316,6 +317,18 @@ pub enum IdeviceError {
|
||||
#[error("disable memory limit failed")]
|
||||
DisableMemoryLimitFailed,
|
||||
|
||||
#[cfg(feature = "tunnel_tcp_stack")]
|
||||
#[error("failed to connect to TCP socket")]
|
||||
ConnectionError(#[from] smoltcp::socket::tcp::ConnectError),
|
||||
|
||||
#[cfg(feature = "tunnel_tcp_stack")]
|
||||
#[error("tunnel thread is closed")]
|
||||
TunnelThreadClosed,
|
||||
|
||||
#[cfg(feature = "tunnel_tcp_stack")]
|
||||
#[error("channel is closed")]
|
||||
ChannelClosed,
|
||||
|
||||
#[error("not enough bytes, expected {1}, got {0}")]
|
||||
NotEnoughBytes(usize, usize),
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use clap::{Arg, Command};
|
||||
use idevice::{
|
||||
core_device_proxy::{self},
|
||||
xpc::XPCDevice,
|
||||
IdeviceService,
|
||||
};
|
||||
use tun_rs::AbstractDevice;
|
||||
@@ -62,38 +63,57 @@ async fn main() {
|
||||
let mut tun_proxy = core_device_proxy::CoreDeviceProxy::connect(&*provider)
|
||||
.await
|
||||
.expect("Unable to connect");
|
||||
let response = tun_proxy.establish_tunnel().await.unwrap();
|
||||
let rsd_port = tun_proxy.handshake.server_rsd_port;
|
||||
|
||||
let dev = tun_rs::create(&tun_rs::Configuration::default()).unwrap();
|
||||
dev.add_address_v6(response.client_parameters.address.parse().unwrap(), 32)
|
||||
.unwrap();
|
||||
dev.set_mtu(response.client_parameters.mtu).unwrap();
|
||||
dev.set_network_address(
|
||||
response.client_parameters.address,
|
||||
response.client_parameters.netmask.parse().unwrap(),
|
||||
Some(response.server_address.parse().unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
let mut tunnel = tun_proxy.create_software_tunnel().unwrap();
|
||||
let channel = tunnel.connect_tcp(rsd_port).unwrap();
|
||||
let client = XPCDevice::new(Box::new(channel)).await.expect("no xpc??");
|
||||
todo!();
|
||||
|
||||
let async_dev = tun_rs::AsyncDevice::new(dev).unwrap();
|
||||
async_dev.enabled(true).unwrap();
|
||||
println!("-----------------------------");
|
||||
println!("tun device created: {:?}", async_dev.name());
|
||||
println!("server address: {}", response.server_address);
|
||||
println!("rsd port: {}", response.server_rsd_port);
|
||||
println!("-----------------------------");
|
||||
|
||||
let mut buf = vec![0; 1500];
|
||||
loop {
|
||||
tokio::select! {
|
||||
Ok(len) = async_dev.recv(&mut buf) => {
|
||||
println!("tun pkt: {:?}", &buf[..len]);
|
||||
tun_proxy.send(&buf[..len]).await.unwrap();
|
||||
}
|
||||
Ok(res) = tun_proxy.recv() => {
|
||||
println!("dev pkt: {:?}", &res);
|
||||
async_dev.send(&res).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
// let dev = tun_rs::create(&tun_rs::Configuration::default()).unwrap();
|
||||
// dev.add_address_v6(
|
||||
// tun_proxy
|
||||
// .handshake
|
||||
// .client_parameters
|
||||
// .address
|
||||
// .parse()
|
||||
// .unwrap(),
|
||||
// 32,
|
||||
// )
|
||||
// .unwrap();
|
||||
// dev.set_mtu(tun_proxy.handshake.client_parameters.mtu)
|
||||
// .unwrap();
|
||||
// dev.set_network_address(
|
||||
// tun_proxy.handshake.client_parameters.address.clone(),
|
||||
// tun_proxy
|
||||
// .handshake
|
||||
// .client_parameters
|
||||
// .netmask
|
||||
// .parse()
|
||||
// .unwrap(),
|
||||
// Some(tun_proxy.handshake.server_address.parse().unwrap()),
|
||||
// )
|
||||
// .unwrap();
|
||||
//
|
||||
// let async_dev = tun_rs::AsyncDevice::new(dev).unwrap();
|
||||
// async_dev.enabled(true).unwrap();
|
||||
// println!("-----------------------------");
|
||||
// println!("tun device created: {:?}", async_dev.name());
|
||||
// println!("server address: {}", tun_proxy.handshake.server_address);
|
||||
// println!("rsd port: {}", tun_proxy.handshake.server_rsd_port);
|
||||
// println!("-----------------------------");
|
||||
//
|
||||
// let mut buf = vec![0; 1500];
|
||||
// loop {
|
||||
// tokio::select! {
|
||||
// Ok(len) = async_dev.recv(&mut buf) => {
|
||||
// println!("tun pkt: {:?}", &buf[..len]);
|
||||
// tun_proxy.send(&buf[..len]).await.unwrap();
|
||||
// }
|
||||
// Ok(res) = tun_proxy.recv() => {
|
||||
// println!("dev pkt: {:?}", &res);
|
||||
// async_dev.send(&res).await.unwrap();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user