Use smoltcp as a software TUN manager (broken)

This commit is contained in:
Jackson Coxson
2025-03-13 13:53:03 -06:00
parent fc9bdafe93
commit e8225b03bc
7 changed files with 680 additions and 67 deletions

184
Cargo.lock generated
View File

@@ -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]]

View File

@@ -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",
]

View 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
}
}

View 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(()))
}
}

View File

@@ -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)
}
}

View File

@@ -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),

View File

@@ -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();
// }
// }
// }
}