Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Pakin
0d544cf6c3 add feature proxy 2025-09-02 12:47:37 +07:00
6 changed files with 684 additions and 43 deletions

127
Cargo.lock generated
View file

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

View file

@ -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 = []
default = ["ffs_proxy"]
ptrace = []
ffs_proxy = []

View file

@ -1,2 +1,5 @@
#[cfg(feature = "ptrace")]
pub mod ptrace;
#[cfg(feature = "ffs_proxy")]
pub mod proxy;

510
src/backend/proxy.rs Normal file
View file

@ -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<u8> 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<u8> 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<T: Sized>(p: &T) -> &[u8] {
std::slice::from_raw_parts((p as *const T) as *const u8, size_of::<T>())
}
/// 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::<UsbInterfaceDescriptor>() 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::<UsbInterfaceDescriptor>()
+ 2 * size_of::<UsbEndpointDescriptor>()
+ size_of::<UsbInterfaceDescriptor>()
+ 2 * size_of::<UsbEndpointDescriptor>();
let header = FfsDescHeadV2 {
magic: MAGIC_V2,
length: (size_of::<FfsDescHeadV2>() + 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<u32> 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: AsyncReadExt + Unpin>(
r: &mut R,
buf: &mut BytesMut,
) -> anyhow::Result<(AdbHdr, Vec<u8>)> {
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: AsyncWriteExt + Unpin>(
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: AsyncWriteExt + Unpin>(
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(())
}

View file

@ -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<i32> {
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::<i32>().ok()
}
@ -24,7 +31,7 @@ fn watch_config(path: PathBuf, cfg: Arc<Mutex<Config>>) -> notify::Result<Recomm
let mut w = notify::recommended_watcher(move |res: Result<notify::Event, _>| {
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<Mutex<Config>>) -> notify::Result<Recomm
w.watch(&saved_path, notify::RecursiveMode::NonRecursive)?;
Ok(w)
}
fn main() -> 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(())
}

19
src/traits.rs Normal file
View file

@ -0,0 +1,19 @@
use std::fmt::Debug;
pub trait EnumerateValue<T> {
/// 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;
}