Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
b718aa3
pass peer stats from gRPC server to session manager
wojcik91 Nov 21, 2025
d40b7ed
add a dedicated type for stats update message
wojcik91 Nov 21, 2025
835e8fd
sketch out basic logic of the session manager
wojcik91 Nov 21, 2025
16ac3d4
setup basic session models
wojcik91 Nov 21, 2025
6e06d15
add session state enum
wojcik91 Nov 21, 2025
f3f7f9d
finish up session map initialization logic
wojcik91 Dec 8, 2025
3c0ecc0
WIP: adding new sessions
wojcik91 Dec 12, 2025
430d8ff
Merge branch 'dev' into vpn_client_session_manager_pt2
wojcik91 Dec 19, 2025
720f5ae
update inputs
wojcik91 Dec 19, 2025
37b009c
post-merge fixes
wojcik91 Dec 19, 2025
86b9567
update flake inputs
wojcik91 Dec 22, 2025
0966d21
handle creating new sessions and add object cache
wojcik91 Dec 23, 2025
483c5ee
update stats model
wojcik91 Jan 2, 2026
b32704e
store sessions stats updates
wojcik91 Jan 2, 2026
339c3cb
clanup unused code
wojcik91 Jan 2, 2026
10badad
parse endpoint
wojcik91 Jan 2, 2026
5f4f697
fetch latest stats for session
wojcik91 Jan 2, 2026
9d1cf47
validate peer stats update order
wojcik91 Jan 5, 2026
a8e12b3
simplify object cache access
wojcik91 Jan 5, 2026
7233bc1
add todo for after merging GW changes
wojcik91 Jan 5, 2026
9fda579
update network stats query
wojcik91 Jan 5, 2026
259aaa3
disable test for now
wojcik91 Jan 5, 2026
7c9bb13
rewrite remaining network stats queries
wojcik91 Jan 5, 2026
a33ed2b
refactor all locations overview queries
wojcik91 Jan 5, 2026
c606874
rewrite device stats queries
wojcik91 Jan 8, 2026
4345c8d
finish refactoring user stats
wojcik91 Jan 8, 2026
584d96d
get last device connection
wojcik91 Jan 8, 2026
227a654
Merge branch 'dev' into vpn_client_session_manager_pt2
wojcik91 Jan 9, 2026
78fa3d6
post-merge fixes
wojcik91 Jan 9, 2026
2441ab0
move sessions migration
wojcik91 Jan 9, 2026
e8ff151
update query cache
wojcik91 Jan 13, 2026
0c85252
Merge branch 'dev' into vpn_client_session_manager_pt2
wojcik91 Jan 15, 2026
e7eeed8
update submodule
wojcik91 Jan 15, 2026
e9f8865
rename migrations
wojcik91 Jan 15, 2026
1903520
post-merge fixes
wojcik91 Jan 15, 2026
bbf548f
remove unused method
wojcik91 Jan 15, 2026
9a2eb0a
fix existing tests
wojcik91 Jan 15, 2026
85bcd0c
comment out tests for now
wojcik91 Jan 16, 2026
f4fabd0
add foreign key to GW table
wojcik91 Jan 16, 2026
2f6eeab
make device id non-optional and add gateway id
wojcik91 Jan 16, 2026
795bc67
update query data
wojcik91 Jan 16, 2026
475d687
cleanup
wojcik91 Jan 16, 2026
f2ed782
disable disconnect for now
wojcik91 Jan 16, 2026
2b11c5f
Merge branch 'dev' into vpn_client_session_manager_pt2
wojcik91 Jan 16, 2026
45a19a3
fix nullable timestamp fields
wojcik91 Jan 19, 2026
80ea30c
fetch inactive sessions
wojcik91 Jan 19, 2026
61d66f7
handle marking sessions as disconnected
wojcik91 Jan 19, 2026
eecad79
store type of MFA used for connection
wojcik91 Jan 19, 2026
f363edd
update query data
wojcik91 Jan 19, 2026
092e13b
Merge branch 'dev' into vpn_client_session_manager_pt2
wojcik91 Jan 19, 2026
48bbf46
setup base stats generator logic
wojcik91 Jan 19, 2026
2438eae
generate random users and devices
wojcik91 Jan 20, 2026
aa54802
move migrations
wojcik91 Jan 20, 2026
7631e45
update dependencies
wojcik91 Jan 20, 2026
febd27f
add indexes
wojcik91 Jan 20, 2026
7996604
Merge branch 'vpn_client_session_manager_pt2' into add_stats_generator
wojcik91 Jan 20, 2026
373669b
Merge branch 'dev' into add_stats_generator
wojcik91 Jan 20, 2026
cfba191
cleanup clippy warnings
wojcik91 Jan 20, 2026
a251d19
clear existing sessions before generator runs
wojcik91 Jan 20, 2026
59247e5
update readme
wojcik91 Jan 20, 2026
7f48ee5
restore pnpm deps
wojcik91 Jan 20, 2026
be2b7d9
add new crate to deny config
wojcik91 Jan 20, 2026
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
15 changes: 15 additions & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ repository = "https://github.com/DefGuard/defguard"
rust-version = "1.85.1"

[workspace]
members = ["crates/*"]
members = ["crates/*", "tools/*"]
default-members = ["crates/*"]
resolver = "2"

[workspace.dependencies]
Expand Down
6 changes: 3 additions & 3 deletions crates/defguard_common/src/db/models/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ impl fmt::Display for Device<Id> {
}
}

impl Distribution<Device<Id>> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Device<Id> {
impl Distribution<Device> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Device {
Device {
id: rng.r#gen(),
id: NoId,
name: Alphanumeric.sample_string(rng, 8),
wireguard_pubkey: Alphanumeric.sample_string(rng, 32),
user_id: rng.r#gen(),
Expand Down
4 changes: 2 additions & 2 deletions crates/defguard_core/src/enterprise/firewall/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ fn random_user_with_id<R: Rng>(rng: &mut R, id: Id) -> User<Id> {
}

fn random_network_device_with_id<R: Rng>(rng: &mut R, id: Id) -> Device<Id> {
let mut device: Device<Id> = rng.r#gen();
device.id = id;
let device: Device = rng.r#gen();
let mut device = device.with_id(id);
device.device_type = DeviceType::Network;
device
}
Expand Down
4 changes: 4 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ exceptions = [
"AGPL-3.0-only",
"AGPL-3.0-or-later",
], crate = "defguard_certs" },
{ allow = [
"AGPL-3.0-only",
"AGPL-3.0-or-later",
], crate = "defguard_generator" },
]

# Some crates don't have (easily) machine readable licensing information,
Expand Down
21 changes: 21 additions & 0 deletions tools/defguard_generator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "defguard_generator"
version = "0.0.0"
edition = "2024"
license-file = "../../LICENSE.md"
homepage = "https://defguard.net/"
repository = "https://github.com/DefGuard/defguard"
rust-version = "1.85.1"

[dependencies]
defguard_common = { workspace = true }
chrono = { workspace = true }
rand = { workspace = true }
clap = { workspace = true, features = ["derive"] }
sqlx = { workspace = true, features = ["postgres", "runtime-tokio-native-tls", "chrono"] }
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
anyhow = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = ["env-filter"] }

[dev-dependencies]
14 changes: 14 additions & 0 deletions tools/defguard_generator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Defguard Object Generator

This crate contains a simple generator for creating users, devices, stats etc during development.

### Usage

```bash
cargo run -p defguard_generator -- vpn-session-stats \
--location-id 1 \
--num-users 10 \
--devices-per-user 2 \
--sessions-per-device 5
```

3 changes: 3 additions & 0 deletions tools/defguard_generator/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod user_devices;
pub mod users;
pub mod vpn_session_stats;
84 changes: 84 additions & 0 deletions tools/defguard_generator/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use defguard_common::db::{Id, init_db};
use defguard_generator::vpn_session_stats::{
VpnSessionGeneratorConfig, generate_vpn_session_stats,
};
use tracing::Level;

#[derive(Parser)]
#[command(about, long_about = None)]
struct Cli {
#[arg(long, env = "DEFGUARD_DB_HOST", default_value = "localhost")]
pub database_host: String,

#[arg(long, env = "DEFGUARD_DB_PORT", default_value_t = 5432)]
pub database_port: u16,

#[arg(long, env = "DEFGUARD_DB_NAME", default_value = "defguard")]
pub database_name: String,

#[arg(long, env = "DEFGUARD_DB_USER", default_value = "defguard")]
pub database_user: String,

#[arg(long, env = "DEFGUARD_DB_PASSWORD", default_value = "")]
pub database_password: String,

#[command(subcommand)]
command: Commands,
}

#[derive(Subcommand)]
enum Commands {
/// generates VPN session stats
VpnSessionStats {
#[arg(long)]
location_id: Id,
#[arg(long)]
num_users: u16,
#[arg(long)]
devices_per_user: u8,
#[arg(long)]
sessions_per_device: u8,
},
}

#[tokio::main]
async fn main() -> Result<()> {
// Initialize logging
tracing_subscriber::fmt().with_max_level(Level::INFO).init();

// parse CLI options
let cli = Cli::parse();

// setup DB pool
let pool = init_db(
&cli.database_host,
cli.database_port,
&cli.database_name,
&cli.database_user,
&cli.database_password,
)
.await;

// execute based on the selected subcommand
match cli.command {
Commands::VpnSessionStats {
location_id,
num_users,
devices_per_user,
sessions_per_device,
} => {
let config = VpnSessionGeneratorConfig {
location_id,
num_users,
devices_per_user,
sessions_per_device,
};

generate_vpn_session_stats(pool, config).await?;
}
};

Ok(())
}
37 changes: 37 additions & 0 deletions tools/defguard_generator/src/user_devices.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use anyhow::Result;
use defguard_common::db::{
Id,
models::{Device, User},
};
use rand::{Rng, rngs::ThreadRng};
use sqlx::PgPool;
use tracing::info;

pub async fn prepare_user_devices(
pool: &PgPool,
rng: &mut ThreadRng,
user: &User<Id>,
devices_per_user: usize,
) -> Result<Vec<Device<Id>>> {
// fetch all existing devices for a given user
let mut user_devices = Device::all_for_username(pool, &user.username).await?;

// if there are enough users just return the required number
if user_devices.len() >= devices_per_user {
info!(
"Found {} existing devices for user {user} in the database. Using the required number.",
user_devices.len()
);
return Ok(user_devices[..devices_per_user].to_vec());
}

// if there are not enough users create new ones
for _ in 0..(devices_per_user - user_devices.len()) {
let mut device: Device = rng.r#gen();
device.user_id = user.id;
let device = device.save(pool).await?;
user_devices.push(device);
}

Ok(user_devices)
}
34 changes: 34 additions & 0 deletions tools/defguard_generator/src/users.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use anyhow::Result;
use defguard_common::db::{Id, models::User};
use rand::{Rng, rngs::ThreadRng};
use sqlx::PgPool;
use tracing::info;

pub async fn prepare_users(
pool: &PgPool,
rng: &mut ThreadRng,
num_users: usize,
) -> Result<Vec<User<Id>>> {
info!("Preparing {num_users} random users for generating VPN session stats");

// fetch all existing users
let mut all_users = User::all(pool).await?;

// if there are enough users just return the required number
if all_users.len() >= num_users {
info!(
"Found {} existing users in the database. Using the required number.",
all_users.len()
);
return Ok(all_users[..num_users].to_vec());
}

// if there are not enough users create new ones
for _ in 0..(num_users - all_users.len()) {
let user: User = rng.r#gen();
let user = user.save(pool).await?;
all_users.push(user);
}

Ok(all_users)
}
Loading
Loading