Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add interface details command #106

Merged
merged 9 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src-tauri/migrations/20231212122824_update_location_stats.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE location_stats ADD COLUMN listen_port INTEGER NOT NULL DEFAULT 0;
ALTER TABLE location_stats ADD COLUMN persistent_keepalive_interval INTEGER NULL;
10 changes: 6 additions & 4 deletions src-tauri/src/bin/defguard-client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ use tauri_plugin_log::LogTarget;

use defguard_client::{
__cmd__active_connection, __cmd__all_connections, __cmd__all_instances, __cmd__all_locations,
__cmd__connect, __cmd__disconnect, __cmd__last_connection, __cmd__location_stats,
__cmd__save_device_config, __cmd__update_instance, __cmd__update_location_routing,
__cmd__connect, __cmd__disconnect, __cmd__last_connection, __cmd__location_interface_details,
__cmd__location_stats, __cmd__save_device_config, __cmd__update_instance,
__cmd__update_location_routing,
appstate::AppState,
commands::{
active_connection, all_connections, all_instances, all_locations, connect, disconnect,
last_connection, location_stats, save_device_config, update_instance,
update_location_routing,
last_connection, location_interface_details, location_stats, save_device_config,
update_instance, update_location_routing,
},
database,
tray::create_tray_menu,
Expand Down Expand Up @@ -79,6 +80,7 @@ async fn main() {
disconnect,
update_instance,
location_stats,
location_interface_details,
all_connections,
last_connection,
active_connection,
Expand Down
71 changes: 70 additions & 1 deletion src-tauri/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{
use chrono::{DateTime, Duration, NaiveDateTime, Utc};
use local_ip_address::local_ip;
use serde::{Deserialize, Serialize};
use sqlx::query;
use std::str::FromStr;
use tauri::{AppHandle, Manager, State};

Expand Down Expand Up @@ -240,7 +241,6 @@ pub async fn all_instances(app_state: State<'_, AppState>) -> Result<Vec<Instanc
#[derive(Serialize, Debug)]
pub struct LocationInfo {
pub id: i64,
// Native id of network from defguard
pub instance_id: i64,
pub name: String,
pub address: String,
Expand Down Expand Up @@ -285,6 +285,75 @@ pub async fn all_locations(

Ok(location_info)
}

#[derive(Serialize, Debug)]
pub struct LocationInterfaceDetails {
pub location_id: i64,
// client interface config
pub name: String, // interface name generated from location name
pub pubkey: String, // own pubkey of client interface
pub address: String, // IP within WireGuard network assigned to the client
pub dns: Option<String>,
pub listen_port: u32,
// peer config
pub peer_pubkey: String,
pub peer_endpoint: String,
pub allowed_ips: String,
pub persistent_keepalive_interval: Option<u16>,
pub last_handshake: i64,
}

#[tauri::command(async)]
pub async fn location_interface_details(
location_id: i64,
app_state: State<'_, AppState>,
) -> Result<LocationInterfaceDetails, Error> {
debug!("Fetching location details for location ID {location_id}");
let pool = app_state.get_pool();
if let Some(location) = Location::find_by_id(&pool, location_id).await? {
debug!("Fetching WireGuard keys for location {}", location.name);
let keys = WireguardKeys::find_by_instance_id(&pool, location.instance_id)
.await?
.ok_or(Error::NotFound)?;
let peer_pubkey = keys.pubkey;

// generate interface name
#[cfg(target_os = "macos")]
let interface_name = get_interface_name();
#[cfg(not(target_os = "macos"))]
let interface_name = get_interface_name(&location);

let result = query!(
r#"
SELECT last_handshake, listen_port as "listen_port!: u32",
persistent_keepalive_interval as "persistent_keepalive_interval?: u16"
FROM location_stats
WHERE location_id = $1 ORDER BY collected_at DESC LIMIT 1
"#,
location_id
)
.fetch_one(&pool)
.await?;

Ok(LocationInterfaceDetails {
location_id,
name: interface_name,
pubkey: location.pubkey,
address: location.address,
dns: location.dns,
listen_port: result.listen_port,
peer_pubkey,
peer_endpoint: location.endpoint,
allowed_ips: location.allowed_ips,
persistent_keepalive_interval: result.persistent_keepalive_interval,
last_handshake: result.last_handshake,
})
} else {
error!("Location ID {location_id} not found");
Err(Error::NotFound)
}
}

#[tauri::command(async)]
pub async fn update_instance(
instance_id: i64,
Expand Down
44 changes: 30 additions & 14 deletions src-tauri/src/database/models/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ pub struct LocationStats {
download: i64,
last_handshake: i64,
collected_at: NaiveDateTime,
listen_port: u32,
persistent_keepalive_interval: Option<u16>,
}

pub async fn peer_to_location_stats(peer: &Peer, pool: &DbPool) -> Result<LocationStats, Error> {
pub async fn peer_to_location_stats(
peer: &Peer,
listen_port: u32,
pool: &DbPool,
) -> Result<LocationStats, Error> {
let location = Location::find_by_public_key(pool, &peer.public_key.to_string()).await?;
Ok(LocationStats {
id: None,
Expand All @@ -43,6 +49,8 @@ pub async fn peer_to_location_stats(peer: &Peer, pool: &DbPool) -> Result<Locati
.map_or(0, |duration| duration.as_secs() as i64)
}),
collected_at: Utc::now().naive_utc(),
listen_port,
persistent_keepalive_interval: peer.persistent_keepalive_interval,
})
}

Expand Down Expand Up @@ -196,6 +204,8 @@ impl LocationStats {
download: i64,
last_handshake: i64,
collected_at: NaiveDateTime,
listen_port: u32,
persistent_keepalive_interval: Option<u16>,
) -> Self {
LocationStats {
id: None,
Expand All @@ -204,19 +214,23 @@ impl LocationStats {
download,
last_handshake,
collected_at,
listen_port,
persistent_keepalive_interval,
}
}

pub async fn save(&mut self, pool: &DbPool) -> Result<(), Error> {
let result = query!(
"INSERT INTO location_stats (location_id, upload, download, last_handshake, collected_at) \
VALUES ($1, $2, $3, $4, $5) \
"INSERT INTO location_stats (location_id, upload, download, last_handshake, collected_at, listen_port, persistent_keepalive_interval) \
VALUES ($1, $2, $3, $4, $5, $6, $7) \
RETURNING id;",
self.location_id,
self.upload,
self.download,
self.last_handshake,
self.collected_at,
self.listen_port,
self.persistent_keepalive_interval,
)
.fetch_one(pool)
.await?;
Expand All @@ -235,21 +249,23 @@ impl LocationStats {
LocationStats,
r#"
WITH cte AS (
SELECT
id, location_id,
COALESCE(upload - LAG(upload) OVER (PARTITION BY location_id ORDER BY collected_at), 0) as upload,
COALESCE(download - LAG(download) OVER (PARTITION BY location_id ORDER BY collected_at), 0) as download,
last_handshake, strftime($1, collected_at) as collected_at
SELECT
id, location_id,
COALESCE(upload - LAG(upload) OVER (PARTITION BY location_id ORDER BY collected_at), 0) as upload,
COALESCE(download - LAG(download) OVER (PARTITION BY location_id ORDER BY collected_at), 0) as download,
last_handshake, strftime($1, collected_at) as collected_at, listen_port, persistent_keepalive_interval
FROM location_stats
ORDER BY collected_at
LIMIT -1 OFFSET 1
)
SELECT
id, location_id,
SUM(MAX(upload, 0)) as "upload!: i64",
SUM(MAX(download, 0)) as "download!: i64",
last_handshake,
collected_at as "collected_at!: NaiveDateTime"
SELECT
id, location_id,
SUM(MAX(upload, 0)) as "upload!: i64",
SUM(MAX(download, 0)) as "download!: i64",
last_handshake,
collected_at as "collected_at!: NaiveDateTime",
listen_port as "listen_port!: u32",
persistent_keepalive_interval as "persistent_keepalive_interval?: u16"
FROM cte
WHERE location_id = $2
AND collected_at >= $3
Expand Down
Loading