diff --git a/Cargo.lock b/Cargo.lock index c63a4c7..cc927d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,7 @@ version = "0.1.0" dependencies = [ "anyhow", "bytes", + "crc32fast", "nix", "notify", "once_cell", @@ -15,10 +16,26 @@ dependencies = [ "serde", "serde_json", "thiserror", + "tokio", "tracing", "tracing-subscriber", ] +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -34,6 +51,21 @@ version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -64,6 +96,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "fsevent-sys" version = "4.1.0" @@ -73,6 +114,12 @@ dependencies = [ "libc", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "inotify" version = "0.11.0" @@ -93,6 +140,17 @@ dependencies = [ "libc", ] +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.3", + "cfg-if", + "libc", +] + [[package]] name = "itoa" version = "1.0.15" @@ -143,6 +201,15 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "1.0.4" @@ -201,6 +268,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -266,6 +342,12 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + [[package]] name = "ryu" version = "1.0.20" @@ -322,12 +404,28 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "syn" version = "2.0.106" @@ -368,6 +466,35 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "pin-project-lite", + "slab", + "socket2", + "tokio-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing" version = "0.1.41" diff --git a/Cargo.toml b/Cargo.toml index addcf2a..2284e29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] anyhow = "1.0.99" bytes = "1.10.1" +crc32fast = "1.5.0" nix = { version = "0.30.1", features = ["ptrace", "process", "uio", "signal"] } notify = "8.2.0" once_cell = "1.21.3" @@ -13,9 +14,11 @@ regex = "1.11.2" serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.143" thiserror = "2.0.16" +tokio = { version = "1.47.1", features = ["rt-multi-thread", "macros", "time", "net", "io-util", "fs"] } tracing = "0.1.41" tracing-subscriber = { version = "0.3.19", features = ["fmt", "ansi"] } [features] -default = ["ptrace"] -ptrace = [] \ No newline at end of file +default = ["ffs_proxy"] +ptrace = [] +ffs_proxy = [] diff --git a/src/backend/mod.rs b/src/backend/mod.rs index e1bb49a..a5b6960 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,2 +1,5 @@ - +#[cfg(feature = "ptrace")] pub mod ptrace; + +#[cfg(feature = "ffs_proxy")] +pub mod proxy; diff --git a/src/backend/proxy.rs b/src/backend/proxy.rs new file mode 100644 index 0000000..77eabb6 --- /dev/null +++ b/src/backend/proxy.rs @@ -0,0 +1,510 @@ +use std::{ + ffi::CString, + fs::OpenOptions, + io::Write, + iter::Enumerate, + os::fd::{AsRawFd, FromRawFd}, + time::Duration, +}; + +use anyhow::{Context, anyhow}; +use bytes::{Buf, BufMut, BytesMut}; +use crc32fast::Hasher; +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::TcpStream, +}; + +use crate::traits::EnumerateValue; + +pub const FFS_EP0: &str = "/dev/usb-ffs/adb/ep0"; +pub const FFS_EP1: &str = "/dev/usb-ffs/adb/ep1"; +pub const FFS_EP2: &str = "/dev/usb-ffs/adb/ep2"; + +pub const ENDPOINT_XFER_BULK: u8 = 2; + +// FFS Descriptors +#[repr(C, packed)] +struct FfsDescHeadV2 { + magic: u32, // FUNCTIONFS_DESCRIPTORS_MAGIC_V2 = 0xB8 0x4B 0x3F 0x94 + length: u32, + flags: u32, // FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC +} + +#[allow(non_snake_case)] +#[repr(C, packed)] +struct UsbInterfaceDescriptor { + bLength: u8, + bDescriptiorType: u8, + bInterfaceNumber: u8, + bAlternateSetting: u8, + bNumEndpoints: u8, + bInterfaceClass: u8, + bInterfaceSubClass: u8, + bInterfaceProtocol: u8, + iInterface: u8, +} + +/// REF: https://vovkos.github.io/doxyrest/samples/libusb/struct_libusb_endpoint_descriptor.html +#[allow(non_snake_case)] +#[repr(C, packed)] +struct UsbEndpointDescriptor { + /// Size of descriptor (bytes) + bLength: u8, + /// Descriptor type + bDescriptorType: u8, + /// Address of endpoint + /// Bit 0-3 = endpoint number + /// Bit 4-6 = reserved + /// Bit 7 = direction + bEndpointAddress: u8, + /// Attributes apply to endpoint + /// Bit 0-1 = transfer type + /// Bit 2-3 = isochronus endpoint + /// Bit 4-5 = isochronus endpoint + /// Bit 6-7 = reserved + bmAttributes: u8, + /// Packet size capable of send/receive + wMaxPacketSize: u16, + /// Interval for polling endpoint for data transfer + bInterval: u8, + /// Audio only: rate at which synchronization feedback is provided + bRefresh: u8, // not used for bulk + /// Audio only: address if synch endpoint + bSynchAddress: u8, // not used for bulk +} + +#[allow(non_camel_case_types)] +#[derive(Debug, Clone)] +enum DescriptorType { + LIBUSB_DT_DEVICE = 0x01, + LIBUSB_DT_CONFIG, + LIBUSB_DT_STRING, + LIBUSB_DT_INTERFACE, + LIBUSB_DT_ENDPOINT, + LIBUSB_DT_BOS = 0x0f, + LIBUSB_DT_DEVICE_CAPABILITY, + LIBUSB_DT_HID = 0x21, + LIBUSB_DT_REPORT, + LIBUSB_DT_PHYSICAL, + LIBUSB_DT_HUB = 0x29, + LIBUSB_DT_SUPERSPEED_HUB, + LIBUSB_DT_SS_ENDPOINT_COMPANION = 0x30, +} + +impl EnumerateValue for DescriptorType { + fn name(&self) -> String + where + Self: std::fmt::Debug, + { + format!("{:?}", self) + } + + fn value(&self) -> u8 + where + Self: Clone, + { + self.clone() as u8 + } + + fn get(val: u8) -> Self { + return unsafe { std::mem::transmute::<_, Self>(val) }; + } +} + +#[allow(non_camel_case_types)] +#[derive(Debug, Clone)] +enum EndpointDirection { + ENDPOINT_IN = 0x80, // device -> host + ENDPOINT_OUT = 0x00, // host -> device +} + +impl EnumerateValue for EndpointDirection { + fn name(&self) -> String + where + Self: std::fmt::Debug, + { + format!("{:?}", self) + } + + fn value(&self) -> u8 + where + Self: Clone, + { + self.clone() as u8 + } + + fn get(val: u8) -> Self { + return unsafe { std::mem::transmute::<_, Self>(val) }; + } +} + +unsafe fn any_as_bytes(p: &T) -> &[u8] { + std::slice::from_raw_parts((p as *const T) as *const u8, size_of::()) +} + +/// Build tiny FS+HS descriptor set for ADB +/// class 0xFF +/// subclass 0x42 +/// proto 0x01 +fn write_ffs_descriptors(ep0: &mut std::fs::File) -> anyhow::Result<()> { + let interface = UsbInterfaceDescriptor { + bLength: size_of::() as u8, + bDescriptiorType: DescriptorType::LIBUSB_DT_INTERFACE.value(), + bInterfaceNumber: 0, + bAlternateSetting: 0, + bNumEndpoints: 2, + bInterfaceClass: 0xFF, + bInterfaceSubClass: 0x42, + bInterfaceProtocol: 0x01, + iInterface: 1, + }; + let fs_out = UsbEndpointDescriptor { + bLength: 7, + bDescriptorType: DescriptorType::LIBUSB_DT_ENDPOINT.value(), + bEndpointAddress: 0x01 | EndpointDirection::ENDPOINT_OUT.value(), + bmAttributes: ENDPOINT_XFER_BULK, + wMaxPacketSize: 64u16.to_le(), + bInterval: 0, + bRefresh: 0, + bSynchAddress: 0, + }; + let fs_in = UsbEndpointDescriptor { + bLength: 7, + bDescriptorType: DescriptorType::LIBUSB_DT_ENDPOINT.value(), + bEndpointAddress: 0x82 | EndpointDirection::ENDPOINT_IN.value(), + bmAttributes: ENDPOINT_XFER_BULK, + wMaxPacketSize: 64u16.to_le(), + bInterval: 0, + bRefresh: 0, + bSynchAddress: 0, + }; + let hs_out = UsbEndpointDescriptor { + wMaxPacketSize: 512u16.to_le(), + ..fs_out + }; + let hs_in = UsbEndpointDescriptor { + wMaxPacketSize: 512u16.to_le(), + ..fs_in + }; + + // header + const MAGIC_V2: u32 = 0xB84B3F94; + // body + let body_len = size_of::() + + 2 * size_of::() + + size_of::() + + 2 * size_of::(); + + let header = FfsDescHeadV2 { + magic: MAGIC_V2, + length: (size_of::() + body_len) as u32, + flags: 0x3, + }; + + // write descriptors + let mut buf = Vec::with_capacity(header.length as usize); + buf.extend_from_slice(unsafe { any_as_bytes(&header) }); + buf.extend_from_slice(unsafe { any_as_bytes(&interface) }); + buf.extend_from_slice(unsafe { any_as_bytes(&fs_out) }); + buf.extend_from_slice(unsafe { any_as_bytes(&fs_in) }); + buf.extend_from_slice(unsafe { any_as_bytes(&interface) }); + buf.extend_from_slice(unsafe { any_as_bytes(&hs_out) }); + buf.extend_from_slice(unsafe { any_as_bytes(&hs_in) }); + + ep0.write_all(&buf)?; + + // header v2 + #[repr(C, packed)] + struct FfsStrHeadV2 { + magic: u32, + length: u32, + str_count: u32, + lang_count: u32, + } + + const STR_MAGIC_V2: u32 = 0xC6 | (0x85 << 8) | (0x93 << 16) | (0x9F << 24); + let sh = FfsStrHeadV2 { + magic: STR_MAGIC_V2, + length: 0, + str_count: 1, + lang_count: 1, + }; + + let s0 = CString::new("ADB Interface").unwrap(); + let mut sbuf = Vec::new(); + sbuf.extend_from_slice(unsafe { any_as_bytes(&sh) }); + sbuf.extend_from_slice(&0x0409u16.to_le_bytes()); + sbuf.extend_from_slice(s0.as_bytes_with_nul()); + + let len_le = (sbuf.len() as u32).to_le_bytes(); + sbuf[4..8].copy_from_slice(&len_le); + ep0.write_all(&sbuf)?; + + Ok(()) +} + +// ADB Helper +#[repr(C, packed)] +#[derive(Clone, Copy)] +struct AdbHdr { + cmd: u32, + arg0: u32, + arg1: u32, + data_len: u32, + data_crc32: u32, + magic: u32, +} +#[derive(Debug, Clone)] +enum ADB_COMMAND { + CNXN = 0x4E584E43, + AUTH = 0x48545541, + OPEN = 0x4E45504F, + OKAY = 0x59414B4F, + CLSE = 0x45534C43, + WRTE = 0x45545257, +} + +impl EnumerateValue for ADB_COMMAND { + fn name(&self) -> String + where + Self: std::fmt::Debug, + { + format!("{:?}", self) + } + + fn value(&self) -> u32 + where + Self: Clone, + { + self.clone() as u32 + } + + fn get(val: u32) -> Self { + return unsafe { std::mem::transmute::<_, Self>(val) }; + } +} + +fn hdr_ok(h: &AdbHdr) -> bool { + h.magic == (h.cmd ^ 0xffffffff) +} + +async fn read_frame_r( + r: &mut R, + buf: &mut BytesMut, +) -> anyhow::Result<(AdbHdr, Vec)> { + while buf.len() < 24 { + let n = r.read_buf(buf).await?; + if n == 0 { + return Err(anyhow!("eof")); + } + } + + let mut h = AdbHdr { + cmd: u32::from_le_bytes(buf[0..4].try_into().unwrap()), + arg0: u32::from_le_bytes(buf[4..8].try_into().unwrap()), + arg1: u32::from_le_bytes(buf[8..12].try_into().unwrap()), + data_len: u32::from_le_bytes(buf[12..16].try_into().unwrap()), + data_crc32: u32::from_le_bytes(buf[16..20].try_into().unwrap()), + magic: u32::from_le_bytes(buf[20..24].try_into().unwrap()), + }; + + if !hdr_ok(&h) { + return Err(anyhow!("bad magic")); + } + + buf.advance(24); + while buf.len() < h.data_len as usize { + let n = r.read_buf(buf).await?; + if n == 0 { + return Err(anyhow!("eof")); + } + } + let payload = buf.split_to(h.data_len as usize).to_vec(); + + Ok((h, payload)) +} + +async fn write_frame_w( + w: &mut W, + mut h: AdbHdr, + payload: &[u8], +) -> anyhow::Result<()> { + let mut hasher = Hasher::new(); + hasher.update(payload); + h.data_len = payload.len() as u32; + h.data_crc32 = hasher.finalize(); + h.magic = h.cmd ^ 0xffffffff; + + let mut b = BytesMut::with_capacity(24 + payload.len()); + for v in [h.cmd, h.arg0, h.arg1, h.data_len, h.data_crc32, h.magic] { + b.put_u32_le(v); + } + + b.extend_from_slice(payload); + w.write_all(&b).await?; + Ok(()) +} + +fn service_from_open_payload(bytes: &[u8]) -> String { + let s = std::str::from_utf8(bytes).unwrap_or_default(); + s.trim_end_matches('\0').to_string() +} + +fn suspicious(service: &str) -> bool { + let s = service.to_ascii_lowercase(); + s.starts_with("shell:su") + || s.contains("setenforce") + || s.starts_with("tcpip:") + || s.contains("pm grant") + || s.contains("appops") +} + +async fn reject_stream_to_host( + w: &mut W, + local_id: u32, + reason: &str, +) -> anyhow::Result<()> { + // OKAY L,0 (ack stream so host accepts WRTE) + write_frame_w( + w, + AdbHdr { + cmd: ADB_COMMAND::OKAY.value(), + arg0: local_id, + arg1: 0, + data_len: 0, + data_crc32: 0, + magic: 0, + }, + &[], + ) + .await?; + // WRTE L,0 with reason + write_frame_w( + w, + AdbHdr { + cmd: ADB_COMMAND::WRTE.value(), + arg0: local_id, + arg1: 0, + data_len: 0, + data_crc32: 0, + magic: 0, + }, + reason.as_bytes(), + ) + .await?; + // CLSE L,0 + write_frame_w( + w, + AdbHdr { + cmd: ADB_COMMAND::CLSE.value(), + arg0: local_id, + arg1: 0, + data_len: 0, + data_crc32: 0, + magic: 0, + }, + &[], + ) + .await?; + Ok(()) +} + +// probing check IN vs OUT +fn open_ffs_endpoints() -> anyhow::Result<(std::fs::File, std::fs::File)> { + let f1 = OpenOptions::new() + .read(true) + .write(true) + .open(FFS_EP1) + .with_context(|| format!("open {FFS_EP1}"))?; + let f2 = OpenOptions::new() + .read(true) + .write(true) + .open(FFS_EP2) + .with_context(|| format!("open {FFS_EP2}"))?; + + let mut a = f1.try_clone()?; + let mut b = f2.try_clone()?; + let w1 = a.write(&[0u8; 0]).map(|_| true).unwrap_or(false); + let w2 = b.write(&[0u8; 0]).map(|_| true).unwrap_or(false); + + let w1b = if !w1 { + a.write(&[0x41]).map(|n| n == 1).unwrap_or(false) + } else { + w1 + }; + let w2b = if !w2 { + b.write(&[0x41]).map(|n| n == 1).unwrap_or(false) + } else { + w2 + }; + + if w1b && !w2b { + Ok((f1, f2)) + } else if w2b && !w1b { + Ok((f2, f1)) + } else { + Ok((f2, f1)) + } +} + +pub async fn run() -> anyhow::Result<()> { + let mut ep0 = OpenOptions::new() + .read(true) + .write(true) + .open(FFS_EP0) + .context("open ep0")?; + write_ffs_descriptors(&mut ep0).context("write FFS descriptors")?; + + let (ep_in_file, ep_out_file) = open_ffs_endpoints().context("open endpoints")?; + + let mut ffs_in = + tokio::fs::File::from_std(unsafe { std::fs::File::from_raw_fd(ep_in_file.as_raw_fd()) }); + let mut ffs_out = + tokio::fs::File::from_std(unsafe { std::fs::File::from_raw_fd(ep_out_file.as_raw_fd()) }); + + let mut adbd = loop { + match TcpStream::connect("127.0.0.1:5566").await { + Ok(s) => break s, + Err(e) => { + eprintln!("wait adbd 5566: {e}"); + tokio::time::sleep(Duration::from_millis(500)).await; + } + } + }; + + let mut hb = BytesMut::with_capacity(64 * 1024); + let mut db = BytesMut::with_capacity(64 * 1024); + + println!("proxy ready"); + + loop { + tokio::select! { + h2d = read_frame_r(&mut ffs_out, &mut hb) => { + let (h, payload) = match h2d { Ok(v)=>v, Err(e)=> { eprintln!("ffs_out read: {e}"); break; } }; + if h.cmd == ADB_COMMAND::OPEN.value() { + let service = service_from_open_payload(&payload); + if suspicious(&service) { + let reason = format!("rejected by policy: {service}"); + if let Err(e) = reject_stream_to_host(&mut ffs_in, h.arg0, &reason).await { + eprintln!("reject write: {e}"); + break; + } + continue; // do not forward to adbd + } + } + if let Err(e) = write_frame_w(&mut adbd, h, &payload).await { + eprintln!("to adbd: {e}"); break; + } + } + d2h = read_frame_r(&mut adbd, &mut db) => { + let (h, payload) = match d2h { Ok(v)=>v, Err(e)=> { eprintln!("adbd read: {e}"); break; } }; + if let Err(e) = write_frame_w(&mut ffs_in, h, &payload).await { + eprintln!("to host: {e}"); break; + } + } + } + } + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index c824823..055ecba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,13 @@ -use std::{path::PathBuf, sync::{Arc, Mutex}, time::Duration}; - +use std::{ + path::PathBuf, + sync::{Arc, Mutex}, + time::Duration, +}; use config::Config; use notify::{RecommendedWatcher, Watcher}; use rule::RuleSet; -use tracing::{info, error}; +use tracing::{error, info}; use tracing_subscriber::FmtSubscriber; mod adb; @@ -12,9 +15,13 @@ mod backend; mod broadcaster; mod config; mod rule; +mod traits; fn pidof(name: &str) -> Option { - let out = std::process::Command::new("pidof").arg(name).output().ok()?; + let out = std::process::Command::new("pidof") + .arg(name) + .output() + .ok()?; let s = String::from_utf8_lossy(&out.stdout).trim().to_string(); s.split_whitespace().next()?.parse::().ok() } @@ -24,7 +31,7 @@ fn watch_config(path: PathBuf, cfg: Arc>) -> notify::Result| { if let Ok(event) = res { if event.kind.is_modify() { - if let Ok(newc) = Config::load(path.clone().to_str().unwrap()){ + if let Ok(newc) = Config::load(path.clone().to_str().unwrap()) { *cfg.lock().unwrap() = newc; } } @@ -33,40 +40,12 @@ fn watch_config(path: PathBuf, cfg: Arc>) -> notify::Result anyhow::Result<()> { - let sub = FmtSubscriber::builder().without_time().with_target(false).finish(); - tracing::subscriber::set_global_default(sub).ok(); - - let mut args = std::env::args().skip(1); - let cfg_path = args.next().filter(|s| s=="--config").and_then(|_| args.next()).unwrap_or_else(|| "/data/adb/modules/adbguard/adbguard.json".into()); - let cfg0 = Config::load(&cfg_path)?; - let cfg = Arc::new(Mutex::new(cfg0)); - let _w = watch_config((&cfg_path).into(), cfg.clone()).ok(); - - loop { - let pid = loop { - if let Some(p) = pidof("adbd"){ - break p; - } - std::thread::sleep(Duration::from_secs(1)); - }; - - info!("attaching to adbd {}", pid); - - let snapshot = { - cfg.lock().unwrap().clone() - }; - let rules = RuleSet::from_cfg(&snapshot); - let action = snapshot.broadcast_action.clone(); - - #[cfg(feature = "ptrace")] - { - if let Err(e) = backend::ptrace::run(pid, rules, action, snapshot.debounce(), snapshot.max_payload_peek){ - error!("backend exited, {e:?}"); - } - } - std::thread::sleep(Duration::from_secs(1)); - +#[tokio::main(flavor = "multi_thread")] +async fn main() -> anyhow::Result<()> { + #[cfg(feature = "ffs_proxy")] + { + backend::proxy::run().await?; } + + Ok(()) } diff --git a/src/traits.rs b/src/traits.rs new file mode 100644 index 0000000..01cfe0f --- /dev/null +++ b/src/traits.rs @@ -0,0 +1,19 @@ +use std::fmt::Debug; + +pub trait EnumerateValue { + /// get enum name + fn name(&self) -> String + where + Self: Debug, + { + format!("{:?}", self) + } + + /// get value of enum + fn value(&self) -> T + where + Self: Clone; + + /// get enum from expected type + fn get(val: T) -> Self; +}