mirror of
https://github.com/yuezk/GlobalProtect-openconnect.git
synced 2025-05-20 07:26:58 -04:00
refactor: Add logger
This commit is contained in:
@@ -15,6 +15,7 @@ serde_json = "1.0"
|
||||
async-trait = "0.1"
|
||||
ring = "0.16"
|
||||
data-encoding = "2.3"
|
||||
log = "0.4"
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
|
@@ -7,6 +7,7 @@ use crate::RequestPool;
|
||||
use crate::Response;
|
||||
use crate::SOCKET_PATH;
|
||||
use crate::{Request, VpnStatus};
|
||||
use log::{info, warn, debug};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
use std::sync::Arc;
|
||||
@@ -107,16 +108,16 @@ impl Client {
|
||||
}
|
||||
|
||||
pub async fn run(&self) {
|
||||
info!("Connecting to the background service...");
|
||||
|
||||
// TODO exit the loop properly
|
||||
loop {
|
||||
match self.connect_to_server().await {
|
||||
Ok(_) => {
|
||||
println!("Disconnected from server, reconnecting...");
|
||||
debug!("Disconnected from server, reconnecting...");
|
||||
}
|
||||
Err(err) => {
|
||||
println!(
|
||||
"Disconnected from server with error: {:?}, reconnecting...",
|
||||
err
|
||||
)
|
||||
debug!("Error connecting to server, retrying, error: {:?}", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,10 +145,13 @@ impl Client {
|
||||
));
|
||||
|
||||
*self.is_healthy.write().await = true;
|
||||
println!("Connected to server");
|
||||
info!("Connected to the background service");
|
||||
|
||||
let _ = tokio::join!(read_handle, write_handle);
|
||||
*self.is_healthy.write().await = false;
|
||||
|
||||
// TODO connection was lost, cleanup the request pool and notify the UI
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -208,22 +212,25 @@ async fn handle_read(
|
||||
Some(id) => request_pool.complete_request(id, response).await,
|
||||
None => {
|
||||
if let Err(err) = server_event_tx.send(response.into()).await {
|
||||
println!("Error sending response to output channel: {}", err);
|
||||
warn!("Error sending response to output channel: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) if err.kind() == io::ErrorKind::ConnectionAborted => {
|
||||
println!("Server disconnected");
|
||||
warn!("Disconnected from the background service");
|
||||
if let Err(err) = server_event_tx.send(ServerEvent::ServerDisconnected).await {
|
||||
println!("Error sending server disconnected event: {}", err);
|
||||
warn!(
|
||||
"Error sending server disconnected event to channel: {}",
|
||||
err
|
||||
);
|
||||
}
|
||||
cancel_token.cancel();
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error reading from server: {}", err);
|
||||
warn!("Error reading from server: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -240,15 +247,15 @@ async fn handle_write(
|
||||
tokio::select! {
|
||||
Some(request) = request_rx.recv() => {
|
||||
if let Err(err) = writer.write(&request).await {
|
||||
println!("Error writing to server: {}", err);
|
||||
warn!("Error writing to server: {}", err);
|
||||
}
|
||||
}
|
||||
_ = cancel_token.cancelled() => {
|
||||
println!("The read loop has been cancelled, exiting the write loop");
|
||||
info!("The read loop has been cancelled, exiting the write loop");
|
||||
break;
|
||||
}
|
||||
else => {
|
||||
println!("Error reading command from channel");
|
||||
warn!("Error reading command from channel");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ use crate::Response;
|
||||
use crate::ResponseData;
|
||||
use crate::VpnStatus;
|
||||
use crate::Writer;
|
||||
use log::{debug, info, warn};
|
||||
use std::sync::Arc;
|
||||
use tokio::io::{self, ReadHalf, WriteHalf};
|
||||
use tokio::net::UnixStream;
|
||||
@@ -29,12 +30,13 @@ async fn handle_read(
|
||||
}
|
||||
|
||||
if !authenticated.unwrap_or(false) {
|
||||
println!("Client not authenticated");
|
||||
warn!("Client not authenticated, closing connection");
|
||||
cancel_token.cancel();
|
||||
break;
|
||||
}
|
||||
|
||||
println!("Received request: {:?}", request);
|
||||
debug!("Received client request: {:?}", request);
|
||||
|
||||
let command = request.command();
|
||||
let context = server_context.clone().into();
|
||||
|
||||
@@ -48,13 +50,13 @@ async fn handle_read(
|
||||
}
|
||||
|
||||
Err(err) if err.kind() == io::ErrorKind::ConnectionAborted => {
|
||||
println!("Client disconnected");
|
||||
info!("Client disconnected");
|
||||
cancel_token.cancel();
|
||||
break;
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
println!("Error receiving command: {:?}", err);
|
||||
warn!("Error receiving request: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,19 +72,17 @@ async fn handle_write(
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(response) = response_rx.recv() => {
|
||||
println!("Sending response: {:?}", response);
|
||||
debug!("Sending response: {:?}", response);
|
||||
if let Err(err) = writer.write(&response).await {
|
||||
println!("Error sending response: {:?}", err);
|
||||
} else {
|
||||
println!("Response sent");
|
||||
warn!("Error sending response: {:?}", err);
|
||||
}
|
||||
}
|
||||
_ = cancel_token.cancelled() => {
|
||||
println!("Exiting write loop");
|
||||
info!("Exiting the write loop");
|
||||
break;
|
||||
}
|
||||
else => {
|
||||
println!("Error receiving response");
|
||||
warn!("Error receiving response from channel");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,21 +95,21 @@ async fn handle_status_change(
|
||||
) {
|
||||
// Send the initial status
|
||||
send_status(&status_rx, &response_tx).await;
|
||||
println!("Waiting for status change");
|
||||
debug!("Waiting for status change");
|
||||
let start_time = std::time::Instant::now();
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = status_rx.changed() => {
|
||||
println!("Status changed: {:?}", start_time.elapsed());
|
||||
debug!("Status changed: {:?}", start_time.elapsed());
|
||||
send_status(&status_rx, &response_tx).await;
|
||||
}
|
||||
_ = cancel_token.cancelled() => {
|
||||
println!("Exiting status loop");
|
||||
info!("Exiting the status loop");
|
||||
break;
|
||||
}
|
||||
else => {
|
||||
println!("Error receiving status");
|
||||
warn!("Error receiving status from channel");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ async fn send_status(status_rx: &watch::Receiver<VpnStatus>, response_tx: &mpsc:
|
||||
.send(Response::from(ResponseData::Status(status)))
|
||||
.await
|
||||
{
|
||||
println!("Error sending status: {:?}", err);
|
||||
warn!("Error sending status: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +132,7 @@ pub(crate) async fn handle_connection(socket: UnixStream, context: Arc<ServerCon
|
||||
let cancel_token = CancellationToken::new();
|
||||
let status_rx = context.vpn().status_rx().await;
|
||||
|
||||
// Read requests from the client
|
||||
let read_handle = tokio::spawn(handle_read(
|
||||
read_stream,
|
||||
context.clone(),
|
||||
@@ -140,12 +141,14 @@ pub(crate) async fn handle_connection(socket: UnixStream, context: Arc<ServerCon
|
||||
cancel_token.clone(),
|
||||
));
|
||||
|
||||
// Write responses to the client
|
||||
let write_handle = tokio::spawn(handle_write(
|
||||
write_stream,
|
||||
response_rx,
|
||||
cancel_token.clone(),
|
||||
));
|
||||
|
||||
// Watch for status changes
|
||||
let status_handle = tokio::spawn(handle_status_change(
|
||||
status_rx,
|
||||
response_tx.clone(),
|
||||
@@ -154,7 +157,7 @@ pub(crate) async fn handle_connection(socket: UnixStream, context: Arc<ServerCon
|
||||
|
||||
let _ = tokio::join!(read_handle, write_handle, status_handle);
|
||||
|
||||
println!("Connection closed")
|
||||
debug!("Client connection closed");
|
||||
}
|
||||
|
||||
fn peer_pid(socket: &UnixStream) -> Option<i32> {
|
||||
@@ -164,9 +167,10 @@ fn peer_pid(socket: &UnixStream) -> Option<i32> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - Implement authentication
|
||||
fn authenticate(peer_pid: Option<i32>) -> bool {
|
||||
if let Some(pid) = peer_pid {
|
||||
println!("Peer PID: {}", pid);
|
||||
info!("Peer PID: {}", pid);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@@ -1,4 +1,5 @@
|
||||
use crate::{connection::handle_connection, vpn::Vpn};
|
||||
use log::{warn, info};
|
||||
use std::{future::Future, os::unix::prelude::PermissionsExt, path::Path, sync::Arc};
|
||||
use tokio::fs;
|
||||
use tokio::net::{UnixListener, UnixStream};
|
||||
@@ -39,7 +40,7 @@ impl Server {
|
||||
}
|
||||
|
||||
let listener = UnixListener::bind(&self.socket_path)?;
|
||||
println!("Listening on socket: {:?}", listener.local_addr()?);
|
||||
info!("Listening on socket: {:?}", listener.local_addr()?);
|
||||
|
||||
let metadata = fs::metadata(&self.socket_path).await?;
|
||||
let mut permissions = metadata.permissions();
|
||||
@@ -49,11 +50,11 @@ impl Server {
|
||||
loop {
|
||||
match listener.accept().await {
|
||||
Ok((socket, _)) => {
|
||||
println!("Accepted connection: {:?}", socket.peer_addr()?);
|
||||
info!("Accepted connection: {:?}", socket.peer_addr()?);
|
||||
tokio::spawn(handle_connection(socket, self.context.clone()));
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error accepting connection: {:?}", err);
|
||||
warn!("Error accepting connection: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,18 +74,15 @@ pub async fn run(
|
||||
let server = Server::new(socket_path.to_string());
|
||||
|
||||
if server.is_running().await {
|
||||
println!("Server is already running");
|
||||
return Ok(());
|
||||
return Err("Another instance of the server is already running".into());
|
||||
}
|
||||
|
||||
tokio::select! {
|
||||
res = server.start() => {
|
||||
if let Err(err) = res {
|
||||
println!("Error starting server: {:?}", err);
|
||||
}
|
||||
res?
|
||||
},
|
||||
_ = shutdown => {
|
||||
println!("Shutting down");
|
||||
info!("Shutting down the server...");
|
||||
server.stop().await?;
|
||||
},
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
use log::{debug, info, trace, warn};
|
||||
use std::ffi::c_void;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
@@ -28,9 +29,28 @@ extern "C" fn on_vpn_connected(value: i32, sender: *mut c_void) {
|
||||
}
|
||||
|
||||
// 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 ::std::os::raw::c_char) {
|
||||
println!("{}: {:?}", level, unsafe {
|
||||
std::ffi::CStr::from_ptr(message)
|
||||
});
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
use log::{warn, info, debug};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ffi::{c_void, CString};
|
||||
use std::sync::Arc;
|
||||
@@ -43,7 +44,7 @@ impl StatusHolder {
|
||||
fn set(&mut self, status: VpnStatus) {
|
||||
self.status = status;
|
||||
if let Err(err) = self.status_tx.send(status) {
|
||||
println!("Failed to send VPN status: {}", err);
|
||||
warn!("Failed to send VPN status: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,17 +114,17 @@ impl Vpn {
|
||||
status_holder.blocking_lock().set(VpnStatus::Connecting);
|
||||
let ret = unsafe { ffi::connect(&oc_options) };
|
||||
|
||||
println!("VPN connection closed with code: {}", ret);
|
||||
info!("VPN connection closed with code: {}", ret);
|
||||
status_holder.blocking_lock().set(VpnStatus::Disconnected);
|
||||
});
|
||||
|
||||
println!("Waiting for the VPN connection...");
|
||||
info!("Waiting for the VPN connection...");
|
||||
|
||||
if let Some(cmd_pipe_fd) = vpn_rx.recv().await {
|
||||
println!("VPN connection started, code: {}", cmd_pipe_fd);
|
||||
info!("VPN connection started, cmd_pipe_fd: {}", cmd_pipe_fd);
|
||||
self.status_holder.lock().await.set(VpnStatus::Connected);
|
||||
} else {
|
||||
println!("VPN connection failed to start");
|
||||
warn!("VPN connection failed to start");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -131,17 +132,20 @@ impl Vpn {
|
||||
|
||||
pub async fn disconnect(&self) {
|
||||
if self.status().await == VpnStatus::Disconnected {
|
||||
println!("VPN already disconnected");
|
||||
info!("VPN already disconnected, skipping disconnect");
|
||||
return;
|
||||
}
|
||||
|
||||
info!("Disconnecting VPN...");
|
||||
unsafe { ffi::disconnect() };
|
||||
// Wait for the VPN to disconnect
|
||||
println!("VPN disconnect waiting for disconnect...");
|
||||
|
||||
let mut status_rx = self.status_rx().await;
|
||||
debug!("Waiting for the VPN to disconnect...");
|
||||
|
||||
|
||||
while status_rx.changed().await.is_ok() {
|
||||
if *status_rx.borrow() == VpnStatus::Disconnected {
|
||||
info!("VPN disconnected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,9 @@
|
||||
#include <stdio.h>
|
||||
#include <openconnect.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <openconnect.h>
|
||||
|
||||
#include "vpn.h"
|
||||
|
||||
@@ -16,27 +15,27 @@ const char *g_vpnc_script;
|
||||
/* Validate the peer certificate */
|
||||
static int validate_peer_cert(__attribute__((unused)) void *_vpninfo, const char *reason)
|
||||
{
|
||||
printf("Validating peer cert: %s\n", reason);
|
||||
INFO("Validating peer cert: %s", reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Print progress messages */
|
||||
static void print_progress(__attribute__((unused)) void *_vpninfo, int level, const char *fmt, ...)
|
||||
static void print_progress(__attribute__((unused)) void *_vpninfo, int level, const char *format, ...)
|
||||
{
|
||||
FILE *outf = level ? stdout : stderr;
|
||||
va_list args;
|
||||
|
||||
char ts[64];
|
||||
time_t t = time(NULL);
|
||||
struct tm *tm = localtime(&t);
|
||||
|
||||
strftime(ts, 64, "[%Y-%m-%d %H:%M:%S] ", tm);
|
||||
fprintf(outf, "%s", ts);
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(outf, fmt, args);
|
||||
va_start(args, format);
|
||||
char *message = format_message(format, args);
|
||||
va_end(args);
|
||||
fflush(outf);
|
||||
|
||||
if (message == NULL)
|
||||
{
|
||||
ERROR("Failed to format log message");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(level, message);
|
||||
free(message);
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_tun_handler(void *_vpninfo)
|
||||
@@ -58,7 +57,7 @@ int vpn_connect(const Options *options)
|
||||
|
||||
if (!vpninfo)
|
||||
{
|
||||
printf("openconnect_vpninfo_new failed\n");
|
||||
ERROR("openconnect_vpninfo_new failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -71,7 +70,7 @@ int vpn_connect(const Options *options)
|
||||
g_cmd_pipe_fd = openconnect_setup_cmd_pipe(vpninfo);
|
||||
if (g_cmd_pipe_fd < 0)
|
||||
{
|
||||
printf("openconnect_setup_cmd_pipe failed\n");
|
||||
ERROR("openconnect_setup_cmd_pipe failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -83,7 +82,7 @@ int vpn_connect(const Options *options)
|
||||
// Essential step
|
||||
if (openconnect_make_cstp_connection(vpninfo) != 0)
|
||||
{
|
||||
printf("openconnect_make_cstp_connection failed\n");
|
||||
ERROR("openconnect_make_cstp_connection failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -98,15 +97,15 @@ int vpn_connect(const Options *options)
|
||||
while (1)
|
||||
{
|
||||
int ret = openconnect_mainloop(vpninfo, 300, 10);
|
||||
printf("openconnect_mainloop returned %d\n", ret);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
INFO("openconnect_mainloop returned %d, exiting", ret);
|
||||
openconnect_vpninfo_free(vpninfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf("openconnect_mainloop returned\n");
|
||||
INFO("openconnect_mainloop returned 0, reconnecting");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +115,6 @@ void vpn_disconnect()
|
||||
char cmd = OC_CMD_CANCEL;
|
||||
if (write(g_cmd_pipe_fd, &cmd, 1) < 0)
|
||||
{
|
||||
printf("Stopping VPN failed\n");
|
||||
ERROR("Failed to write to command pipe, VPN connection may not be stopped");
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,62 @@
|
||||
typedef struct Options {
|
||||
const char *server;
|
||||
const char *cookie;
|
||||
const char *script;
|
||||
void *user_data;
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <openconnect.h>
|
||||
|
||||
typedef struct Options
|
||||
{
|
||||
const char *server;
|
||||
const char *cookie;
|
||||
const char *script;
|
||||
void *user_data;
|
||||
} Options;
|
||||
|
||||
int vpn_connect(const Options *options);
|
||||
void vpn_disconnect();
|
||||
|
||||
extern void on_vpn_connected(int cmd_pipe_fd, void *user_data);
|
||||
extern void vpn_log(int level, const char *msg);
|
||||
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__)
|
||||
|
Reference in New Issue
Block a user