Refactor using Tauri (#278)

This commit is contained in:
Kevin Yue
2024-01-16 22:18:20 +08:00
committed by GitHub
parent edc13ed14d
commit 04a916a3e1
199 changed files with 10153 additions and 7203 deletions

View 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);
}
}

View 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");
}
}

View 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__)