From 1cf31449d64219e8f75d3899ae01707554ed8d40 Mon Sep 17 00:00:00 2001 From: Kevin Yue Date: Sun, 4 Feb 2024 07:47:11 +0800 Subject: [PATCH] Support specify csd-wrapper --- Cargo.lock | 1 + Cargo.toml | 1 + apps/gpservice/src/vpn_task.rs | 37 +++++++++++++++------ crates/gpapi/Cargo.toml | 1 + crates/gpapi/src/gateway/hip.rs | 51 +++++++++++++++++++++++++++++ crates/gpapi/src/gateway/mod.rs | 1 + crates/gpapi/src/gp_params.rs | 12 +++++++ crates/gpapi/src/process/users.rs | 5 +++ crates/gpapi/src/service/request.rs | 22 +++++++++++++ crates/openconnect/src/ffi/vpn.c | 3 ++ 10 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 crates/gpapi/src/gateway/hip.rs diff --git a/Cargo.lock b/Cargo.lock index 600a7db..f25c378 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1438,6 +1438,7 @@ dependencies = [ "roxmltree", "serde", "serde_json", + "serde_urlencoded", "specta", "specta-macros", "tauri", diff --git a/Cargo.toml b/Cargo.toml index 7ce3ab7..f577252 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ thiserror = "1" redact-engine = "0.1" dotenvy_macro = "0.15" compile-time = "0.2" +serde_urlencoded = "0.7" [profile.release] opt-level = 'z' # Optimize for size diff --git a/apps/gpservice/src/vpn_task.rs b/apps/gpservice/src/vpn_task.rs index 55424a1..1ff152e 100644 --- a/apps/gpservice/src/vpn_task.rs +++ b/apps/gpservice/src/vpn_task.rs @@ -10,7 +10,7 @@ use tokio::sync::{mpsc, oneshot, watch, RwLock}; use tokio_util::sync::CancellationToken; pub(crate) struct VpnTaskContext { - vpn_handle: Arc>>, + vpn_handle: Arc>>, vpn_state_tx: Arc>, disconnect_rx: RwLock>>, } @@ -32,16 +32,18 @@ impl VpnTaskContext { } let info = req.info().clone(); - let vpn_handle = self.vpn_handle.clone(); + let vpn_handle = Arc::clone(&self.vpn_handle); let args = req.args(); let vpn = Vpn::builder(req.gateway().server(), args.cookie()) .user_agent(args.user_agent()) .script(args.vpnc_script()) + .csd_uid(args.csd_uid()) + .csd_wrapper(args.csd_wrapper()) .os(args.openconnect_os()) .build(); // Save the VPN handle - vpn_handle.write().await.replace(vpn); + vpn_handle.write().unwrap().replace(vpn); let vpn_state_tx = self.vpn_state_tx.clone(); let connect_info = Box::new(info.clone()); @@ -55,17 +57,30 @@ impl VpnTaskContext { thread::spawn(move || { let vpn_state_tx_clone = vpn_state_tx.clone(); - vpn_handle.blocking_read().as_ref().map(|vpn| { - vpn.connect(move || { - let connect_info = Box::new(info.clone()); - vpn_state_tx.send(VpnState::Connected(connect_info)).ok(); + if let Err(err) = vpn_handle.read().map(|vpn| { + vpn.as_ref().map(|vpn| { + vpn.connect(move || { + let connect_info = Box::new(info.clone()); + vpn_state_tx.send(VpnState::Connected(connect_info)).ok(); + }) }) - }); + }) { + info!("VPN connect failed: {:?}", err); + } + // .as_ref().map(|vpn| { + // vpn.connect(move || { + // let connect_info = Box::new(info.clone()); + // vpn_state_tx.send(VpnState::Connected(connect_info)).ok(); + // }) + // }); + + // println!("VPN connect result: {:?}", ret); // Notify the VPN is disconnected vpn_state_tx_clone.send(VpnState::Disconnected).ok(); // Remove the VPN handle - vpn_handle.blocking_write().take(); + // vpn_handle.blocking_write().take(); + vpn_handle.write().unwrap().take(); disconnect_tx.send(()).ok(); }); @@ -73,7 +88,9 @@ impl VpnTaskContext { pub async fn disconnect(&self) { if let Some(disconnect_rx) = self.disconnect_rx.write().await.take() { - if let Some(vpn) = self.vpn_handle.read().await.as_ref() { + info!("Disconnecting VPN..."); + if let Some(vpn) = self.vpn_handle.read().unwrap().as_ref() { + info!("VPN is connected, start disconnecting..."); self.vpn_state_tx.send(VpnState::Disconnecting).ok(); vpn.disconnect() } diff --git a/crates/gpapi/Cargo.toml b/crates/gpapi/Cargo.toml index ee8fa37..78831a5 100644 --- a/crates/gpapi/Cargo.toml +++ b/crates/gpapi/Cargo.toml @@ -25,6 +25,7 @@ url.workspace = true regex.workspace = true dotenvy_macro.workspace = true uzers.workspace = true +serde_urlencoded.workspace = true tauri = { workspace = true, optional = true } clap = { workspace = true, optional = true } diff --git a/crates/gpapi/src/gateway/hip.rs b/crates/gpapi/src/gateway/hip.rs new file mode 100644 index 0000000..743e0e9 --- /dev/null +++ b/crates/gpapi/src/gateway/hip.rs @@ -0,0 +1,51 @@ +use std::collections::HashMap; + +use anyhow::bail; +use reqwest::Client; + +use crate::{gp_params::GpParams, utils::normalize_server}; + +async fn retrieve_config(gateway: &str, cookie: &str, gp_params: &GpParams) -> anyhow::Result<()> { + let url = normalize_server(gateway)?; + + let config_url = format!("{}/ssl-vpn/getconfig.esp", url); + let client = Client::builder() + .danger_accept_invalid_certs(gp_params.ignore_tls_errors()) + .user_agent(gp_params.user_agent()) + .build()?; + + let mut params = serde_urlencoded::from_str::>(cookie)?; + + println!("{:?}", params); + + params.insert("client-type", "1"); + params.insert("protocol-version", "p1"); + params.insert("internal", "no"); + params.insert("ipv6-support", "yes"); + params.insert("clientos", gp_params.client_os()); + params.insert("hmac-algo", "sha1,md5,sha256"); + params.insert("enc-algo", "aes-128-cbc,aes-256-cbc"); + + if let Some(os_version) = gp_params.os_version() { + params.insert("os-version", os_version); + } + if let Some(client_version) = gp_params.client_version() { + params.insert("app-version", client_version); + } + + let res = client.post(&config_url).form(¶ms).send().await?; + let status = res.status(); + + if status.is_client_error() || status.is_server_error() { + bail!("Retrieve config error: {}", status) + } + + let res_xml = res.text().await?; + println!("{}", res_xml); + + Ok(()) +} + +pub async fn hip_report(gateway: &str, cookie: &str, gp_params: &GpParams) -> anyhow::Result<()> { + retrieve_config(gateway, cookie, gp_params).await +} diff --git a/crates/gpapi/src/gateway/mod.rs b/crates/gpapi/src/gateway/mod.rs index ab84223..b768269 100644 --- a/crates/gpapi/src/gateway/mod.rs +++ b/crates/gpapi/src/gateway/mod.rs @@ -1,5 +1,6 @@ mod login; mod parse_gateways; +pub mod hip; pub use login::*; pub(crate) use parse_gateways::*; diff --git a/crates/gpapi/src/gp_params.rs b/crates/gpapi/src/gp_params.rs index 0c2a205..03322ac 100644 --- a/crates/gpapi/src/gp_params.rs +++ b/crates/gpapi/src/gp_params.rs @@ -83,6 +83,18 @@ impl GpParams { self.prefer_default_browser } + pub fn client_os(&self) -> &str { + self.client_os.as_str() + } + + pub fn os_version(&self) -> Option<&str> { + self.os_version.as_deref() + } + + pub fn client_version(&self) -> Option<&str> { + self.client_version.as_deref() + } + pub(crate) fn to_params(&self) -> HashMap<&str, &str> { let mut params: HashMap<&str, &str> = HashMap::new(); let client_os = self.client_os.as_str(); diff --git a/crates/gpapi/src/process/users.rs b/crates/gpapi/src/process/users.rs index 0fc51ef..265f1d4 100644 --- a/crates/gpapi/src/process/users.rs +++ b/crates/gpapi/src/process/users.rs @@ -23,6 +23,11 @@ pub fn get_non_root_user() -> anyhow::Result { Ok(user) } +pub fn get_current_user() -> anyhow::Result { + let current_user = whoami::username(); + get_user_by_name(¤t_user) +} + fn get_real_user() -> anyhow::Result { // Read the UID from SUDO_UID or PKEXEC_UID environment variable if available. let uid = match env::var("SUDO_UID") { diff --git a/crates/gpapi/src/service/request.rs b/crates/gpapi/src/service/request.rs index e80f68e..a457197 100644 --- a/crates/gpapi/src/service/request.rs +++ b/crates/gpapi/src/service/request.rs @@ -32,6 +32,8 @@ pub struct ConnectArgs { cookie: String, vpnc_script: Option, user_agent: Option, + csd_uid: u32, + csd_wrapper: Option, os: Option, } @@ -42,6 +44,8 @@ impl ConnectArgs { vpnc_script: None, user_agent: None, os: None, + csd_uid: 0, + csd_wrapper: None, } } @@ -60,6 +64,14 @@ impl ConnectArgs { pub fn openconnect_os(&self) -> Option { self.os.as_ref().map(|os| os.to_openconnect_os().to_string()) } + + pub fn csd_uid(&self) -> u32 { + self.csd_uid + } + + pub fn csd_wrapper(&self) -> Option { + self.csd_wrapper.clone() + } } #[derive(Debug, Deserialize, Serialize, Type)] @@ -81,6 +93,16 @@ impl ConnectRequest { self } + pub fn with_csd_uid(mut self, csd_uid: u32) -> Self { + self.args.csd_uid = csd_uid; + self + } + + pub fn with_csd_wrapper>>(mut self, csd_wrapper: T) -> Self { + self.args.csd_wrapper = csd_wrapper.into(); + self + } + pub fn with_user_agent>>(mut self, user_agent: T) -> Self { self.args.user_agent = user_agent.into(); self diff --git a/crates/openconnect/src/ffi/vpn.c b/crates/openconnect/src/ffi/vpn.c index 265a4e2..f4e6423 100644 --- a/crates/openconnect/src/ffi/vpn.c +++ b/crates/openconnect/src/ffi/vpn.c @@ -143,6 +143,9 @@ int vpn_connect(const vpn_options *options, vpn_connected_callback callback) void vpn_disconnect() { char cmd = OC_CMD_CANCEL; + + INFO("Stopping VPN connection: %d", g_cmd_pipe_fd); + if (write(g_cmd_pipe_fd, &cmd, 1) < 0) { ERROR("Failed to write to command pipe, VPN connection may not be stopped");