diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..072b46e Binary files /dev/null and b/.DS_Store differ diff --git a/Cargo.lock b/Cargo.lock index 1a6951a..c30a69c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -753,9 +753,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.3" +version = "1.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" dependencies = [ "jobserver", "libc", @@ -1617,12 +1617,11 @@ name = "frida_core" version = "0.2.0" dependencies = [ "base64 0.22.1", + "cc", "chrono", "filedescriptor", "futures", - "libc", "log", - "nix", "rand", "serde", "serde_derive", diff --git a/frida_client/src/client.rs b/frida_client/src/client.rs index c305c9a..1b42223 100644 --- a/frida_client/src/client.rs +++ b/frida_client/src/client.rs @@ -205,10 +205,18 @@ pub mod desktop { use log::info; use tokio::net::UdpSocket; - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "macos"))] use regex::Regex; + fn cmd(cmd: &str, args: &[&str]) -> String { + let ecode = std::process::Command::new(cmd) + .args(args) + .output(); + assert!(ecode.is_ok(), "Failed to execte {}", cmd); + std::str::from_utf8(&ecode.as_ref().unwrap().stdout).unwrap().to_string() + } + #[cfg(target_os = "linux")] fn configure_routes(endpoint_ip: &str) { let mut if_out = std::process::Command::new("ip") @@ -306,6 +314,37 @@ pub mod desktop { } } + #[cfg(target_os = "macos")] + fn configure_routes(endpoint_ip: &str) { + let mut if_out = cmd("route", &["-n", "get", "default"]); + let r = std::str::from_utf8(&if_out.as_bytes()).unwrap(); + + let mut gateway = None; + let mut if_name = None; + + let ui = r.find("gateway: ").unwrap() + 9; + let s = &r[ui..]; + let ei = s.find("\n").unwrap(); + gateway = Some(&s[..ei]); + + let ui = r.find("interface: ").unwrap() + 11; + let s = &r[ui..]; + let ei = s.find("\n").unwrap(); + if_name = Some(&s[..ei]); + + info!("Main interface: {:?}", &if_name.unwrap()); + + let inter_name = if_name.unwrap(); + + info!("Main network interface: {:?}", &gateway.unwrap()); + + cmd("route", &["add", "-host", endpoint_ip, &gateway.unwrap()]); + + cmd("route", &["change", "default", "-interface", "utun3"]); // todo: change that + + cmd("route", &["add", "-host", endpoint_ip, &gateway.unwrap()]); + } + pub struct DesktopClient { pub client_config: ClientConfiguration } @@ -330,12 +369,15 @@ pub mod desktop { let mut client = CoreVpnClient{ client_config: self.client_config.clone(), close_token: tokio_util::sync::CancellationToken::new()}; info!("Platform specific code"); - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "macos"))] { let s_a: std::net::SocketAddr = self.client_config.server.endpoint.parse().unwrap(); configure_routes(&s_a.ip().to_string()); } + #[cfg(target_os = "macos")] + sock.connect(&self.client_config.server.endpoint).await.unwrap(); + client.start(sock, dev_reader, dev_writer, mtu).await; } } diff --git a/frida_core/Cargo.toml b/frida_core/Cargo.toml index f73940c..ed8c4b2 100644 --- a/frida_core/Cargo.toml +++ b/frida_core/Cargo.toml @@ -25,12 +25,11 @@ tokio = { workspace = true } [target.'cfg(target_os="windows")'.dependencies] wintun = "0.5.0" -[target.'cfg(target_os="macos")'.dependencies] -nix = { version = "0.29.0", features = ["socket"] } - [target.'cfg(target_os="linux")'.dependencies] tokio-tun = "0.12.1" [target.'cfg(target_os="android")'.dependencies] -libc = "0.2" -filedescriptor = "0.8.2" \ No newline at end of file +filedescriptor = "0.8.2" + +[target.'cfg(target_os="macos")'.build-dependencies] +cc = "1.2.13" \ No newline at end of file diff --git a/frida_core/build.rs b/frida_core/build.rs new file mode 100644 index 0000000..aab01ab --- /dev/null +++ b/frida_core/build.rs @@ -0,0 +1,7 @@ +use cc; + +fn main() { + if cfg!(target_os = "macos") { + cc::Build::new().file("src/c/utun.c").compile("utun"); + } +} \ No newline at end of file diff --git a/frida_core/src/android_tun.rs b/frida_core/src/android_tun.rs index 573421a..5e1c415 100644 --- a/frida_core/src/android_tun.rs +++ b/frida_core/src/android_tun.rs @@ -1,4 +1,3 @@ -//use tokio::fs::File; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use std::error::Error; use std::os::fd::FromRawFd; @@ -6,7 +5,6 @@ use std::os::fd::FromRawFd; use std::fs::File; use std::io::{Write, Read}; -use libc::fdopen; use std::ffi::CString; pub fn create(cfg: i32) -> (DeviceReader, DeviceWriter) { diff --git a/frida_core/src/c/utun.c b/frida_core/src/c/utun.c new file mode 100644 index 0000000..57f6864 --- /dev/null +++ b/frida_core/src/c/utun.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int32_t open_utun(uint64_t num) { + int err; + int fd; + struct sockaddr_ctl addr; + struct ctl_info info; + + fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + if (fd < 0) { + return fd; + } + memset(&info, 0, sizeof (info)); + strncpy(info.ctl_name, UTUN_CONTROL_NAME, strlen(UTUN_CONTROL_NAME)); + err = ioctl(fd, CTLIOCGINFO, &info); + if (err < 0) { + close(fd); + return err; + } + + addr.sc_id = info.ctl_id; + addr.sc_len = sizeof(addr); + addr.sc_family = AF_SYSTEM; + addr.ss_sysaddr = AF_SYS_CONTROL; + addr.sc_unit = num + 1; // utunX where X is sc.sc_unit -1 + + err = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); + if (err < 0) { + // this utun is in use + close(fd); + return err; + } + return fd; +} \ No newline at end of file diff --git a/frida_core/src/mac_tun.rs b/frida_core/src/mac_tun.rs index c85247a..466fc65 100644 --- a/frida_core/src/mac_tun.rs +++ b/frida_core/src/mac_tun.rs @@ -3,80 +3,39 @@ use std::{ffi::CString, process::Command}; use std::sync::Arc; use std::error::Error; use log::info; -use nix::errno::Errno; -use nix::libc::{connect, sockaddr_ctl, CTLIOCGINFO}; -use nix::sys::socket::{SockaddrLike, SockaddrStorage, UnixAddr}; -use nix::{libc::{ctl_info, PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL}, sys::socket::{socket, AddressFamily, SockFlag, SockProtocol, SockType, sockaddr}}; use tokio::fs::File; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use crate::device::AbstractDevice; -fn cmd(cmd: &str, args: &[&str]) { - let ecode = Command::new("ip") +extern "C" { + fn open_utun(num: u64) -> i32; +} + +fn cmd(cmd: &str, args: &[&str]) -> String { + let ecode = Command::new(cmd) .args(args) - .spawn() - .unwrap() - .wait() - .unwrap(); - assert!(ecode.success(), "Failed to execte {}", cmd); + .output(); + assert!(ecode.is_ok(), "Failed to execte {}", cmd); + std::str::from_utf8(&ecode.as_ref().unwrap().stdout).unwrap().to_string() +} + +fn get_utun() -> (i32, String) { + for utun_n in 0..255 { + let fd = unsafe { open_utun(utun_n) }; + if fd >= 0 { + let name = format!("utun{}", utun_n); + return (fd, name); + } + } + panic!("{}", std::io::Error::last_os_error()) } pub fn create(cfg: AbstractDevice) -> (DeviceReader, DeviceWriter) { - - let fd = socket( - AddressFamily::System, - SockType::Datagram, - SockFlag::empty(), - Some(SockProtocol::KextControl) - ); - - if let Err(e) = fd { - panic!("Unable to open socket! Error: {:?}", e); - } - - let fd = fd.unwrap(); - - let mut info: ctl_info = unsafe { std::mem::zeroed() }; - let ctl_name = CString::new("com.apple.net.utun_control").unwrap(); - ctl_name.as_bytes_with_nul() - .iter() - .enumerate() - .for_each(|(i, &c)| info.ctl_name[i] = c as i8); - - if unsafe { nix::libc::ioctl(fd.as_raw_fd(), CTLIOCGINFO, &mut info) } < 0 { - let err = Errno::last(); - panic!("ioctl CTLIOCGINFO failed: {}", err); - } - - let mut sc = sockaddr_ctl { - sc_len: std::mem::size_of::() as u8, - sc_family: nix::libc::AF_SYSTEM as u8, - ss_sysaddr: nix::libc::AF_SYS_CONTROL as u16, - sc_id: info.ctl_id, - sc_unit: 0, - sc_reserved: [0; 5] - }; - - let asc = &sc as *const sockaddr_ctl as *const sockaddr; - let f = unsafe { connect(fd.as_raw_fd(), asc, size_of::() as u32 ) }; - - info!("utun interface created successfully, fd: {:?}", f); - - let mut reader = unsafe { File::from_raw_fd(f) }; - let mut writer = unsafe { File::from_raw_fd(f) }; - - let mut address = cfg.address.unwrap().to_string(); - address.push_str("/24"); - - /* - cmd("ip", &["addr", "add", "dev", iface.name(), &address]); - cmd("ip", &["link", "set", "up", "dev", iface.name()]); - - let iface = Arc::new(iface); - let writer = Arc::clone(&iface); - let reader = Arc::clone(&iface);*/ - + let (fd, if_name) = get_utun(); + let reader = unsafe { File::from_raw_fd(fd) }; + let writer = unsafe { File::from_raw_fd(fd) }; + cmd("ifconfig", &[&if_name, &cfg.address.unwrap().to_string(), &cfg.destination.unwrap().to_string(), "netmask", &cfg.netmask.unwrap().to_string(), "up"]); (DeviceReader {reader}, DeviceWriter {writer}) }