mirror of
				https://github.com/yuezk/GlobalProtect-openconnect.git
				synced 2025-05-20 07:26:58 -04:00 
			
		
		
		
	Move new code
This commit is contained in:
		
							
								
								
									
										13
									
								
								crates/openconnect/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								crates/openconnect/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "openconnect"
 | 
			
		||||
version.workspace = true
 | 
			
		||||
edition.workspace = true
 | 
			
		||||
license.workspace = true
 | 
			
		||||
links = "openconnect"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
log.workspace = true
 | 
			
		||||
is_executable.workspace = true
 | 
			
		||||
 | 
			
		||||
[build-dependencies]
 | 
			
		||||
cc = "1"
 | 
			
		||||
							
								
								
									
										12
									
								
								crates/openconnect/build.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								crates/openconnect/build.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
fn main() {
 | 
			
		||||
  // Link to the native openconnect library
 | 
			
		||||
  println!("cargo:rustc-link-lib=openconnect");
 | 
			
		||||
  println!("cargo:rerun-if-changed=src/ffi/vpn.c");
 | 
			
		||||
  println!("cargo:rerun-if-changed=src/ffi/vpn.h");
 | 
			
		||||
 | 
			
		||||
  // Compile the vpn.c file
 | 
			
		||||
  cc::Build::new()
 | 
			
		||||
    .file("src/ffi/vpn.c")
 | 
			
		||||
    .include("src/ffi")
 | 
			
		||||
    .compile("vpn");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										71
									
								
								crates/openconnect/src/ffi/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								crates/openconnect/src/ffi/mod.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
use crate::Vpn;
 | 
			
		||||
use log::{debug, info, trace, warn};
 | 
			
		||||
use std::ffi::{c_char, c_int, c_void};
 | 
			
		||||
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub(crate) struct ConnectOptions {
 | 
			
		||||
  pub user_data: *mut c_void,
 | 
			
		||||
 | 
			
		||||
  pub server: *const c_char,
 | 
			
		||||
  pub cookie: *const c_char,
 | 
			
		||||
  pub user_agent: *const c_char,
 | 
			
		||||
 | 
			
		||||
  pub script: *const c_char,
 | 
			
		||||
  pub os: *const c_char,
 | 
			
		||||
  pub certificate: *const c_char,
 | 
			
		||||
  pub servercert: *const c_char,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[link(name = "vpn")]
 | 
			
		||||
extern "C" {
 | 
			
		||||
  #[link_name = "vpn_connect"]
 | 
			
		||||
  fn vpn_connect(
 | 
			
		||||
    options: *const ConnectOptions,
 | 
			
		||||
    callback: extern "C" fn(i32, *mut c_void),
 | 
			
		||||
  ) -> c_int;
 | 
			
		||||
 | 
			
		||||
  #[link_name = "vpn_disconnect"]
 | 
			
		||||
  fn vpn_disconnect();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn connect(options: &ConnectOptions) -> i32 {
 | 
			
		||||
  unsafe { vpn_connect(options, on_vpn_connected) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn disconnect() {
 | 
			
		||||
  unsafe { vpn_disconnect() }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[no_mangle]
 | 
			
		||||
extern "C" fn on_vpn_connected(pipe_fd: i32, vpn: *mut c_void) {
 | 
			
		||||
  let vpn = unsafe { &*(vpn as *const Vpn) };
 | 
			
		||||
  vpn.on_connected(pipe_fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Logger used in the C code.
 | 
			
		||||
// level: 0 = error, 1 = info, 2 = debug, 3 = trace
 | 
			
		||||
// map the error level log in openconnect to the warning level
 | 
			
		||||
#[no_mangle]
 | 
			
		||||
extern "C" fn vpn_log(level: i32, message: *const c_char) {
 | 
			
		||||
  let message = unsafe { std::ffi::CStr::from_ptr(message) };
 | 
			
		||||
  let message = message.to_str().unwrap_or("Invalid log message");
 | 
			
		||||
  // Strip the trailing newline
 | 
			
		||||
  let message = message.trim_end_matches('\n');
 | 
			
		||||
 | 
			
		||||
  if level == 0 {
 | 
			
		||||
    warn!("{}", message);
 | 
			
		||||
  } else if level == 1 {
 | 
			
		||||
    info!("{}", message);
 | 
			
		||||
  } else if level == 2 {
 | 
			
		||||
    debug!("{}", message);
 | 
			
		||||
  } else if level == 3 {
 | 
			
		||||
    trace!("{}", message);
 | 
			
		||||
  } else {
 | 
			
		||||
    warn!(
 | 
			
		||||
      "Unknown log level: {}, enable DEBUG log level to see more details",
 | 
			
		||||
      level
 | 
			
		||||
    );
 | 
			
		||||
    debug!("{}", message);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										144
									
								
								crates/openconnect/src/ffi/vpn.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								crates/openconnect/src/ffi/vpn.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,144 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
#include <openconnect.h>
 | 
			
		||||
 | 
			
		||||
#include "vpn.h"
 | 
			
		||||
 | 
			
		||||
void *g_user_data;
 | 
			
		||||
 | 
			
		||||
static int g_cmd_pipe_fd;
 | 
			
		||||
static const char *g_vpnc_script;
 | 
			
		||||
static vpn_connected_callback on_vpn_connected;
 | 
			
		||||
 | 
			
		||||
/* Validate the peer certificate */
 | 
			
		||||
static int validate_peer_cert(__attribute__((unused)) void *_vpninfo, const char *reason)
 | 
			
		||||
{
 | 
			
		||||
    INFO("Validating peer cert: %s", reason);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Print progress messages */
 | 
			
		||||
static void print_progress(__attribute__((unused)) void *_vpninfo, int level, const char *format, ...)
 | 
			
		||||
{
 | 
			
		||||
    va_list args;
 | 
			
		||||
    va_start(args, format);
 | 
			
		||||
    char *message = format_message(format, args);
 | 
			
		||||
    va_end(args);
 | 
			
		||||
 | 
			
		||||
    if (message == NULL)
 | 
			
		||||
    {
 | 
			
		||||
        ERROR("Failed to format log message");
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        LOG(level, message);
 | 
			
		||||
        free(message);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void setup_tun_handler(void *_vpninfo)
 | 
			
		||||
{
 | 
			
		||||
    int ret = openconnect_setup_tun_device(_vpninfo, g_vpnc_script, NULL);
 | 
			
		||||
    if (!ret) {
 | 
			
		||||
        on_vpn_connected(g_cmd_pipe_fd, g_user_data);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Initialize VPN connection */
 | 
			
		||||
int vpn_connect(const vpn_options *options, vpn_connected_callback callback)
 | 
			
		||||
{
 | 
			
		||||
    INFO("openconnect version: %s", openconnect_get_version());
 | 
			
		||||
    struct openconnect_info *vpninfo;
 | 
			
		||||
    struct utsname utsbuf;
 | 
			
		||||
 | 
			
		||||
    g_user_data = options->user_data;
 | 
			
		||||
    g_vpnc_script = options->script;
 | 
			
		||||
    on_vpn_connected = callback;
 | 
			
		||||
 | 
			
		||||
    INFO("User agent: %s", options->user_agent);
 | 
			
		||||
    INFO("VPNC script: %s", options->script);
 | 
			
		||||
    INFO("OS: %s", options->os);
 | 
			
		||||
 | 
			
		||||
    vpninfo = openconnect_vpninfo_new(options->user_agent, validate_peer_cert, NULL, NULL, print_progress, NULL);
 | 
			
		||||
 | 
			
		||||
    if (!vpninfo)
 | 
			
		||||
    {
 | 
			
		||||
        ERROR("openconnect_vpninfo_new failed");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    openconnect_set_loglevel(vpninfo, PRG_TRACE);
 | 
			
		||||
    openconnect_init_ssl();
 | 
			
		||||
    openconnect_set_protocol(vpninfo, "gp");
 | 
			
		||||
    openconnect_set_hostname(vpninfo, options->server);
 | 
			
		||||
    openconnect_set_cookie(vpninfo, options->cookie);
 | 
			
		||||
 | 
			
		||||
    if (options->os) {
 | 
			
		||||
        openconnect_set_reported_os(vpninfo, options->os);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (options->certificate)
 | 
			
		||||
    {
 | 
			
		||||
        INFO("Setting client certificate: %s", options->certificate);
 | 
			
		||||
        openconnect_set_client_cert(vpninfo, options->certificate, NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (options->servercert) {
 | 
			
		||||
        INFO("Setting server certificate: %s", options->servercert);
 | 
			
		||||
        openconnect_set_system_trust(vpninfo, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_cmd_pipe_fd = openconnect_setup_cmd_pipe(vpninfo);
 | 
			
		||||
    if (g_cmd_pipe_fd < 0)
 | 
			
		||||
    {
 | 
			
		||||
        ERROR("openconnect_setup_cmd_pipe failed");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!uname(&utsbuf))
 | 
			
		||||
    {
 | 
			
		||||
        openconnect_set_localname(vpninfo, utsbuf.nodename);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Essential step
 | 
			
		||||
    if (openconnect_make_cstp_connection(vpninfo) != 0)
 | 
			
		||||
    {
 | 
			
		||||
        ERROR("openconnect_make_cstp_connection failed");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (openconnect_setup_dtls(vpninfo, 60) != 0)
 | 
			
		||||
    {
 | 
			
		||||
        openconnect_disable_dtls(vpninfo);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Essential step
 | 
			
		||||
    openconnect_set_setup_tun_handler(vpninfo, setup_tun_handler);
 | 
			
		||||
 | 
			
		||||
    while (1)
 | 
			
		||||
    {
 | 
			
		||||
        int ret = openconnect_mainloop(vpninfo, 300, 10);
 | 
			
		||||
 | 
			
		||||
        if (ret)
 | 
			
		||||
        {
 | 
			
		||||
            INFO("openconnect_mainloop returned %d, exiting", ret);
 | 
			
		||||
            openconnect_vpninfo_free(vpninfo);
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        INFO("openconnect_mainloop returned 0, reconnecting");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Stop the VPN connection */
 | 
			
		||||
void vpn_disconnect()
 | 
			
		||||
{
 | 
			
		||||
    char cmd = OC_CMD_CANCEL;
 | 
			
		||||
    if (write(g_cmd_pipe_fd, &cmd, 1) < 0)
 | 
			
		||||
    {
 | 
			
		||||
        ERROR("Failed to write to command pipe, VPN connection may not be stopped");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								crates/openconnect/src/ffi/vpn.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								crates/openconnect/src/ffi/vpn.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <openconnect.h>
 | 
			
		||||
 | 
			
		||||
typedef void (*vpn_connected_callback)(int cmd_pipe_fd, void *user_data);
 | 
			
		||||
 | 
			
		||||
typedef struct vpn_options
 | 
			
		||||
{
 | 
			
		||||
    void *user_data;
 | 
			
		||||
    const char *server;
 | 
			
		||||
    const char *cookie;
 | 
			
		||||
    const char *user_agent;
 | 
			
		||||
 | 
			
		||||
    const char *script;
 | 
			
		||||
    const char *os;
 | 
			
		||||
    const char *certificate;
 | 
			
		||||
    const char *servercert;
 | 
			
		||||
} vpn_options;
 | 
			
		||||
 | 
			
		||||
int vpn_connect(const vpn_options *options, vpn_connected_callback callback);
 | 
			
		||||
void vpn_disconnect();
 | 
			
		||||
 | 
			
		||||
extern void vpn_log(int level, const char *msg);
 | 
			
		||||
 | 
			
		||||
static char *format_message(const char *format, va_list args)
 | 
			
		||||
{
 | 
			
		||||
    va_list args_copy;
 | 
			
		||||
    va_copy(args_copy, args);
 | 
			
		||||
    int len = vsnprintf(NULL, 0, format, args_copy);
 | 
			
		||||
    va_end(args_copy);
 | 
			
		||||
 | 
			
		||||
    char *buffer = malloc(len + 1);
 | 
			
		||||
    if (buffer == NULL)
 | 
			
		||||
    {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vsnprintf(buffer, len + 1, format, args);
 | 
			
		||||
    return buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _log(int level, ...)
 | 
			
		||||
{
 | 
			
		||||
    va_list args;
 | 
			
		||||
    va_start(args, level);
 | 
			
		||||
 | 
			
		||||
    char *format = va_arg(args, char *);
 | 
			
		||||
    char *message = format_message(format, args);
 | 
			
		||||
 | 
			
		||||
    va_end(args);
 | 
			
		||||
 | 
			
		||||
    if (message == NULL)
 | 
			
		||||
    {
 | 
			
		||||
        vpn_log(PRG_ERR, "Failed to format log message");
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        vpn_log(level, message);
 | 
			
		||||
        free(message);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define LOG(level, ...) _log(level, __VA_ARGS__)
 | 
			
		||||
#define ERROR(...) LOG(PRG_ERR, __VA_ARGS__)
 | 
			
		||||
#define INFO(...) LOG(PRG_INFO, __VA_ARGS__)
 | 
			
		||||
#define DEBUG(...) LOG(PRG_DEBUG, __VA_ARGS__)
 | 
			
		||||
#define TRACE(...) LOG(PRG_TRACE, __VA_ARGS__)
 | 
			
		||||
							
								
								
									
										5
									
								
								crates/openconnect/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								crates/openconnect/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
mod ffi;
 | 
			
		||||
mod vpn;
 | 
			
		||||
mod vpnc_script;
 | 
			
		||||
 | 
			
		||||
pub use vpn::*;
 | 
			
		||||
							
								
								
									
										131
									
								
								crates/openconnect/src/vpn.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								crates/openconnect/src/vpn.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
			
		||||
use std::{
 | 
			
		||||
  ffi::{c_char, CString},
 | 
			
		||||
  sync::{Arc, RwLock},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use log::info;
 | 
			
		||||
 | 
			
		||||
use crate::{ffi, vpnc_script::find_default_vpnc_script};
 | 
			
		||||
 | 
			
		||||
type OnConnectedCallback = Arc<RwLock<Option<Box<dyn FnOnce() + 'static + Send + Sync>>>>;
 | 
			
		||||
 | 
			
		||||
pub struct Vpn {
 | 
			
		||||
  server: CString,
 | 
			
		||||
  cookie: CString,
 | 
			
		||||
  user_agent: CString,
 | 
			
		||||
  script: CString,
 | 
			
		||||
  os: CString,
 | 
			
		||||
  certificate: Option<CString>,
 | 
			
		||||
  servercert: Option<CString>,
 | 
			
		||||
 | 
			
		||||
  callback: OnConnectedCallback,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Vpn {
 | 
			
		||||
  pub fn builder(server: &str, cookie: &str) -> VpnBuilder {
 | 
			
		||||
    VpnBuilder::new(server, cookie)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pub fn connect(&self, on_connected: impl FnOnce() + 'static + Send + Sync) -> i32 {
 | 
			
		||||
    self
 | 
			
		||||
      .callback
 | 
			
		||||
      .write()
 | 
			
		||||
      .unwrap()
 | 
			
		||||
      .replace(Box::new(on_connected));
 | 
			
		||||
    let options = self.build_connect_options();
 | 
			
		||||
 | 
			
		||||
    ffi::connect(&options)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pub(crate) fn on_connected(&self, pipe_fd: i32) {
 | 
			
		||||
    info!("Connected to VPN, pipe_fd: {}", pipe_fd);
 | 
			
		||||
 | 
			
		||||
    if let Some(callback) = self.callback.write().unwrap().take() {
 | 
			
		||||
      callback();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pub fn disconnect(&self) {
 | 
			
		||||
    ffi::disconnect();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fn build_connect_options(&self) -> ffi::ConnectOptions {
 | 
			
		||||
    ffi::ConnectOptions {
 | 
			
		||||
      user_data: self as *const _ as *mut _,
 | 
			
		||||
 | 
			
		||||
      server: self.server.as_ptr(),
 | 
			
		||||
      cookie: self.cookie.as_ptr(),
 | 
			
		||||
      user_agent: self.user_agent.as_ptr(),
 | 
			
		||||
      script: self.script.as_ptr(),
 | 
			
		||||
      os: self.os.as_ptr(),
 | 
			
		||||
      certificate: Self::option_to_ptr(&self.certificate),
 | 
			
		||||
      servercert: Self::option_to_ptr(&self.servercert),
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fn option_to_ptr(option: &Option<CString>) -> *const c_char {
 | 
			
		||||
    match option {
 | 
			
		||||
      Some(value) => value.as_ptr(),
 | 
			
		||||
      None => std::ptr::null(),
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct VpnBuilder {
 | 
			
		||||
  server: String,
 | 
			
		||||
  cookie: String,
 | 
			
		||||
  user_agent: Option<String>,
 | 
			
		||||
  script: Option<String>,
 | 
			
		||||
  os: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl VpnBuilder {
 | 
			
		||||
  fn new(server: &str, cookie: &str) -> Self {
 | 
			
		||||
    Self {
 | 
			
		||||
      server: server.to_string(),
 | 
			
		||||
      cookie: cookie.to_string(),
 | 
			
		||||
      user_agent: None,
 | 
			
		||||
      script: None,
 | 
			
		||||
      os: None,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pub fn user_agent<T: Into<Option<String>>>(mut self, user_agent: T) -> Self {
 | 
			
		||||
    self.user_agent = user_agent.into();
 | 
			
		||||
    self
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pub fn script<T: Into<Option<String>>>(mut self, script: T) -> Self {
 | 
			
		||||
    self.script = script.into();
 | 
			
		||||
    self
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pub fn os<T: Into<Option<String>>>(mut self, os: T) -> Self {
 | 
			
		||||
    self.os = os.into();
 | 
			
		||||
    self
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pub fn build(self) -> Vpn {
 | 
			
		||||
    let user_agent = self.user_agent.unwrap_or_default();
 | 
			
		||||
    let script = self
 | 
			
		||||
      .script
 | 
			
		||||
      .or_else(find_default_vpnc_script)
 | 
			
		||||
      .unwrap_or_default();
 | 
			
		||||
    let os = self.os.unwrap_or("linux".to_string());
 | 
			
		||||
 | 
			
		||||
    Vpn {
 | 
			
		||||
      server: Self::to_cstring(&self.server),
 | 
			
		||||
      cookie: Self::to_cstring(&self.cookie),
 | 
			
		||||
      user_agent: Self::to_cstring(&user_agent),
 | 
			
		||||
      script: Self::to_cstring(&script),
 | 
			
		||||
      os: Self::to_cstring(&os),
 | 
			
		||||
      certificate: None,
 | 
			
		||||
      servercert: None,
 | 
			
		||||
      callback: Default::default(),
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fn to_cstring(value: &str) -> CString {
 | 
			
		||||
    CString::new(value.to_string()).expect("Failed to convert to CString")
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								crates/openconnect/src/vpnc_script.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								crates/openconnect/src/vpnc_script.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
use is_executable::IsExecutable;
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
 | 
			
		||||
const VPNC_SCRIPT_LOCATIONS: [&str; 5] = [
 | 
			
		||||
  "/usr/local/share/vpnc-scripts/vpnc-script",
 | 
			
		||||
  "/usr/local/sbin/vpnc-script",
 | 
			
		||||
  "/usr/share/vpnc-scripts/vpnc-script",
 | 
			
		||||
  "/usr/sbin/vpnc-script",
 | 
			
		||||
  "/etc/vpnc/vpnc-script",
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
pub(crate) fn find_default_vpnc_script() -> Option<String> {
 | 
			
		||||
  for location in VPNC_SCRIPT_LOCATIONS.iter() {
 | 
			
		||||
    let path = Path::new(location);
 | 
			
		||||
    if path.is_executable() {
 | 
			
		||||
      return Some(location.to_string());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  log::warn!("vpnc-script not found");
 | 
			
		||||
 | 
			
		||||
  None
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user