From 1237e53789e9fdbaf80a303822c3d457cb52334a Mon Sep 17 00:00:00 2001
From: jakub-tldr <78603704+jakub-tldr@users.noreply.github.com>
Date: Fri, 27 Feb 2026 15:28:24 +0100
Subject: [PATCH 01/11] remove block, add info to edit location page
---
crates/defguard_core/src/handlers/wireguard.rs | 11 -----------
web/messages/en/location.json | 2 +-
web/src/pages/EditLocationPage/EditLocationPage.tsx | 3 +--
3 files changed, 2 insertions(+), 14 deletions(-)
diff --git a/crates/defguard_core/src/handlers/wireguard.rs b/crates/defguard_core/src/handlers/wireguard.rs
index 3a8adda26..fa6d02b9a 100644
--- a/crates/defguard_core/src/handlers/wireguard.rs
+++ b/crates/defguard_core/src/handlers/wireguard.rs
@@ -328,17 +328,6 @@ pub(crate) async fn modify_network(
let before = network.clone();
let new_addresses = data.parse_addresses()?;
- // Block network address changes if any device is assigned to the network
- if before.address != new_addresses
- && WireguardNetworkDevice::has_devices_in_network(&appstate.pool, network_id).await?
- {
- return Err(WebError::BadRequest(
- "Cannot change network address while devices are assigned to this network. \
- Remove all devices first."
- .into(),
- ));
- }
-
network.address = new_addresses;
network.allowed_ips = data.parse_allowed_ips();
network.name = data.name;
diff --git a/web/messages/en/location.json b/web/messages/en/location.json
index 7b7bd2fd0..22331a364 100644
--- a/web/messages/en/location.json
+++ b/web/messages/en/location.json
@@ -3,5 +3,5 @@
"location_delete_success": "Location deleted",
"location_delete_failed": "Failed to delete location",
"location_edit_failed": "Failed to update location",
- "location_edit_failed_has_devices": "Gateway VPN IP address and netmask can’t be changed while devices are active on this network. To proceed, remove all devices from the current network first."
+ "location_edit_addresses_rewrite_warning": "Changing the Gateway VPN IP address or netmask will automatically reassign any device addresses that fall outside the new network range to a randomly selected available IP address."
}
diff --git a/web/src/pages/EditLocationPage/EditLocationPage.tsx b/web/src/pages/EditLocationPage/EditLocationPage.tsx
index e1f6440da..5640139a9 100644
--- a/web/src/pages/EditLocationPage/EditLocationPage.tsx
+++ b/web/src/pages/EditLocationPage/EditLocationPage.tsx
@@ -214,7 +214,7 @@ const EditLocationForm = ({ location }: { location: NetworkLocation }) => {
>
@@ -223,7 +223,6 @@ const EditLocationForm = ({ location }: { location: NetworkLocation }) => {
{(field) => (
)}
From 26cc321c49430ec9061df3cc082b269ea34c7975 Mon Sep 17 00:00:00 2001
From: jakub-tldr <78603704+jakub-tldr@users.noreply.github.com>
Date: Mon, 2 Mar 2026 10:08:17 +0100
Subject: [PATCH 02/11] move sql query before invocation
---
.../defguard_common/src/db/models/device.rs | 37 ++++++++++++++-----
.../src/db/models/wireguard.rs | 4 +-
crates/defguard_core/src/lib.rs | 2 +-
.../src/location_management/mod.rs | 14 ++++++-
4 files changed, 43 insertions(+), 14 deletions(-)
diff --git a/crates/defguard_common/src/db/models/device.rs b/crates/defguard_common/src/db/models/device.rs
index e1a143032..acd78ee3d 100644
--- a/crates/defguard_common/src/db/models/device.rs
+++ b/crates/defguard_common/src/db/models/device.rs
@@ -1,4 +1,4 @@
-use std::{fmt, net::IpAddr};
+use std::{collections::HashSet, fmt, net::IpAddr};
use base64::{Engine, prelude::BASE64_STANDARD};
use chrono::{NaiveDate, NaiveDateTime, Timelike, Utc};
@@ -845,6 +845,7 @@ impl Device {
network: &WireguardNetwork,
reserved_ips: Option<&[IpAddr]>,
current_ips: Option<&[IpAddr]>,
+ used_ips: Option<&HashSet>,
) -> Result {
debug!(
"Assiging IP addresses for device: {} in network {}",
@@ -853,6 +854,19 @@ impl Device {
let mut ips = Vec::new();
let reserved = reserved_ips.unwrap_or_default();
+ let fetched;
+ let used_ips: &HashSet = match used_ips {
+ Some(set) => set,
+ None => {
+ fetched = WireguardNetworkDevice::all_for_network(&mut *transaction, network.id)
+ .await?
+ .into_iter()
+ .flat_map(|device| device.wireguard_ips)
+ .collect::>();
+ &fetched
+ }
+ };
+
// Iterate over all network addresses and assign new IP for the device in each of them
for address in &network.address {
debug!(
@@ -872,15 +886,20 @@ impl Device {
}
let mut picked = None;
for ip in address {
- if network
- .can_assign_ips(transaction, &[ip], Some(self.id))
- .await
- .is_ok()
- && !reserved.contains(&ip)
- {
- picked = Some(ip);
- break;
+ if ip == address.network() || ip == address.broadcast() || ip == address.ip() {
+ continue;
+ }
+
+ if used_ips.contains(&ip) || reserved.contains(&ip) {
+ continue;
+ }
+
+ if reserved.contains(&ip) {
+ continue;
}
+
+ picked = Some(ip);
+ break;
}
// Return error if no address can be assigned
diff --git a/crates/defguard_common/src/db/models/wireguard.rs b/crates/defguard_common/src/db/models/wireguard.rs
index 4ca4998c5..9314f2892 100644
--- a/crates/defguard_common/src/db/models/wireguard.rs
+++ b/crates/defguard_common/src/db/models/wireguard.rs
@@ -441,7 +441,7 @@ impl WireguardNetwork {
let devices = self.get_allowed_devices(&mut *transaction).await?;
for device in devices {
device
- .assign_next_network_ip(&mut *transaction, self, None, None)
+ .assign_next_network_ip(&mut *transaction, self, None, None, None)
.await?;
}
Ok(())
@@ -459,7 +459,7 @@ impl WireguardNetwork {
let allowed_device_ids: Vec = allowed_devices.iter().map(|dev| dev.id).collect();
if allowed_device_ids.contains(&device.id) {
let wireguard_network_device = device
- .assign_next_network_ip(&mut *transaction, self, reserved_ips, None)
+ .assign_next_network_ip(&mut *transaction, self, reserved_ips, None, None)
.await?;
Ok(wireguard_network_device)
} else {
diff --git a/crates/defguard_core/src/lib.rs b/crates/defguard_core/src/lib.rs
index bc6ae24ca..ab5f12013 100644
--- a/crates/defguard_core/src/lib.rs
+++ b/crates/defguard_core/src/lib.rs
@@ -762,7 +762,7 @@ pub async fn init_dev_env(config: &DefGuardConfig) {
.await
.expect("Could not save device");
device
- .assign_next_network_ip(&mut transaction, &network, None, None)
+ .assign_next_network_ip(&mut transaction, &network, None, None, None)
.await
.expect("Could not assign IP to device");
}
diff --git a/crates/defguard_core/src/location_management/mod.rs b/crates/defguard_core/src/location_management/mod.rs
index 400be93f6..df15fb52d 100644
--- a/crates/defguard_core/src/location_management/mod.rs
+++ b/crates/defguard_core/src/location_management/mod.rs
@@ -1,4 +1,7 @@
-use std::{collections::HashMap, net::IpAddr};
+use std::{
+ collections::{HashMap, HashSet},
+ net::IpAddr,
+};
use defguard_common::{
csv::AsCsv,
@@ -165,6 +168,12 @@ pub async fn process_device_access_changes(
// Loop through current device configurations; remove no longer allowed, readdress
// when necessary; remove processed entry from all devices list initial list should
// now contain only devices to be added.
+ let all_devices =
+ WireguardNetworkDevice::all_for_network(&mut *transaction, location.id).await?;
+ let used_ips: HashSet = all_devices
+ .into_iter()
+ .flat_map(|device| device.wireguard_ips)
+ .collect();
let mut events: Vec = Vec::new();
for device_network_config in currently_configured_devices {
// Device is allowed and an IP was already assigned
@@ -179,6 +188,7 @@ pub async fn process_device_access_changes(
location,
reserved_ips,
Some(&device_network_config.wireguard_ips),
+ Some(&used_ips),
)
.await?;
events.push(GatewayEvent::DeviceModified(DeviceInfo {
@@ -221,7 +231,7 @@ pub async fn process_device_access_changes(
// Add configs for new allowed devices
for device in allowed_devices.into_values() {
let wireguard_network_device = device
- .assign_next_network_ip(&mut *transaction, location, reserved_ips, None)
+ .assign_next_network_ip(&mut *transaction, location, reserved_ips, None, None)
.await?;
events.push(GatewayEvent::DeviceCreated(DeviceInfo {
device,
From 221e5ad98c08d2b89d13b499e3cf90a7101c6a29 Mon Sep 17 00:00:00 2001
From: jakub-tldr <78603704+jakub-tldr@users.noreply.github.com>
Date: Mon, 2 Mar 2026 10:32:40 +0100
Subject: [PATCH 03/11] create used_ips before
---
.../defguard_common/src/db/models/device.rs | 15 +-------------
.../src/db/models/wireguard.rs | 20 ++++++++++++++++---
crates/defguard_core/src/lib.rs | 12 +++++++++--
.../src/location_management/mod.rs | 11 +++++++---
4 files changed, 36 insertions(+), 22 deletions(-)
diff --git a/crates/defguard_common/src/db/models/device.rs b/crates/defguard_common/src/db/models/device.rs
index acd78ee3d..d4f1362b7 100644
--- a/crates/defguard_common/src/db/models/device.rs
+++ b/crates/defguard_common/src/db/models/device.rs
@@ -843,9 +843,9 @@ impl Device {
&self,
transaction: &mut PgConnection,
network: &WireguardNetwork,
+ used_ips: &HashSet,
reserved_ips: Option<&[IpAddr]>,
current_ips: Option<&[IpAddr]>,
- used_ips: Option<&HashSet>,
) -> Result {
debug!(
"Assiging IP addresses for device: {} in network {}",
@@ -854,19 +854,6 @@ impl Device {
let mut ips = Vec::new();
let reserved = reserved_ips.unwrap_or_default();
- let fetched;
- let used_ips: &HashSet = match used_ips {
- Some(set) => set,
- None => {
- fetched = WireguardNetworkDevice::all_for_network(&mut *transaction, network.id)
- .await?
- .into_iter()
- .flat_map(|device| device.wireguard_ips)
- .collect::>();
- &fetched
- }
- };
-
// Iterate over all network addresses and assign new IP for the device in each of them
for address in &network.address {
debug!(
diff --git a/crates/defguard_common/src/db/models/wireguard.rs b/crates/defguard_common/src/db/models/wireguard.rs
index 9314f2892..81cbd9c87 100644
--- a/crates/defguard_common/src/db/models/wireguard.rs
+++ b/crates/defguard_common/src/db/models/wireguard.rs
@@ -1,5 +1,5 @@
use std::{
- collections::HashMap,
+ collections::{HashMap, HashSet},
fmt::{self, Display},
iter::zip,
net::{IpAddr, Ipv4Addr},
@@ -438,10 +438,16 @@ impl WireguardNetwork {
"Assigning IPs in network {} for all existing devices ",
self
);
+ let all_devices =
+ WireguardNetworkDevice::all_for_network(&mut *transaction, self.id).await?;
+ let used_ips: HashSet = all_devices
+ .into_iter()
+ .flat_map(|device| device.wireguard_ips)
+ .collect();
let devices = self.get_allowed_devices(&mut *transaction).await?;
for device in devices {
device
- .assign_next_network_ip(&mut *transaction, self, None, None, None)
+ .assign_next_network_ip(&mut *transaction, self, &used_ips, None, None)
.await?;
}
Ok(())
@@ -457,9 +463,17 @@ impl WireguardNetwork {
info!("Assigning IP in network {self} for {device}");
let allowed_devices = self.get_allowed_devices(&mut *transaction).await?;
let allowed_device_ids: Vec = allowed_devices.iter().map(|dev| dev.id).collect();
+
+ let all_devices =
+ WireguardNetworkDevice::all_for_network(&mut *transaction, self.id).await?;
+ let used_ips: HashSet = all_devices
+ .into_iter()
+ .flat_map(|device| device.wireguard_ips)
+ .collect();
+
if allowed_device_ids.contains(&device.id) {
let wireguard_network_device = device
- .assign_next_network_ip(&mut *transaction, self, reserved_ips, None, None)
+ .assign_next_network_ip(&mut *transaction, self, &used_ips, reserved_ips, None)
.await?;
Ok(wireguard_network_device)
} else {
diff --git a/crates/defguard_core/src/lib.rs b/crates/defguard_core/src/lib.rs
index ab5f12013..580dfee74 100644
--- a/crates/defguard_core/src/lib.rs
+++ b/crates/defguard_core/src/lib.rs
@@ -1,5 +1,6 @@
#![allow(clippy::too_many_arguments)]
use std::{
+ collections::HashSet,
net::{IpAddr, Ipv4Addr, SocketAddr},
sync::{Arc, LazyLock, Mutex, RwLock},
};
@@ -20,6 +21,7 @@ use defguard_common::{
init_db,
models::{
Device, DeviceType, Settings, User, WireguardNetwork,
+ device::WireguardNetworkDevice,
oauth2client::OAuth2Client,
settings::{initialize_current_settings, update_current_settings},
wireguard::{
@@ -738,7 +740,13 @@ pub async fn init_dev_env(config: &DefGuardConfig) {
.await
.expect("Could not save network")
};
-
+ let all_devices = WireguardNetworkDevice::all_for_network(&mut *transaction, network.id)
+ .await
+ .expect("Failed to query all devices");
+ let used_ips: HashSet = all_devices
+ .into_iter()
+ .flat_map(|device| device.wireguard_ips)
+ .collect();
if Device::find_by_pubkey(
&mut *transaction,
"gQYL5eMeFDj0R+lpC7oZyIl0/sNVmQDC6ckP7husZjc=",
@@ -762,7 +770,7 @@ pub async fn init_dev_env(config: &DefGuardConfig) {
.await
.expect("Could not save device");
device
- .assign_next_network_ip(&mut transaction, &network, None, None, None)
+ .assign_next_network_ip(&mut transaction, &network, &used_ips, None, None)
.await
.expect("Could not assign IP to device");
}
diff --git a/crates/defguard_core/src/location_management/mod.rs b/crates/defguard_core/src/location_management/mod.rs
index df15fb52d..298c29773 100644
--- a/crates/defguard_core/src/location_management/mod.rs
+++ b/crates/defguard_core/src/location_management/mod.rs
@@ -186,9 +186,9 @@ pub async fn process_device_access_changes(
.assign_next_network_ip(
&mut *transaction,
location,
+ &used_ips,
reserved_ips,
Some(&device_network_config.wireguard_ips),
- Some(&used_ips),
)
.await?;
events.push(GatewayEvent::DeviceModified(DeviceInfo {
@@ -227,11 +227,16 @@ pub async fn process_device_access_changes(
}
}
}
-
+ let all_devices =
+ WireguardNetworkDevice::all_for_network(&mut *transaction, location.id).await?;
+ let used_ips: HashSet = all_devices
+ .into_iter()
+ .flat_map(|device| device.wireguard_ips)
+ .collect();
// Add configs for new allowed devices
for device in allowed_devices.into_values() {
let wireguard_network_device = device
- .assign_next_network_ip(&mut *transaction, location, reserved_ips, None, None)
+ .assign_next_network_ip(&mut *transaction, location, &used_ips, reserved_ips, None)
.await?;
events.push(GatewayEvent::DeviceCreated(DeviceInfo {
device,
From 4c1b249a4ce6a91e8e280f39bd8497b6785125f2 Mon Sep 17 00:00:00 2001
From: jakub-tldr <78603704+jakub-tldr@users.noreply.github.com>
Date: Mon, 2 Mar 2026 13:40:13 +0100
Subject: [PATCH 04/11] add helper function
---
.../src/db/models/wireguard.rs | 29 +++--
crates/defguard_core/src/lib.rs | 9 +-
.../src/location_management/mod.rs | 112 ++++++++++++++++--
.../src/vpn_session_stats.rs | 3 +-
4 files changed, 121 insertions(+), 32 deletions(-)
diff --git a/crates/defguard_common/src/db/models/wireguard.rs b/crates/defguard_common/src/db/models/wireguard.rs
index 81cbd9c87..aed2bb593 100644
--- a/crates/defguard_common/src/db/models/wireguard.rs
+++ b/crates/defguard_common/src/db/models/wireguard.rs
@@ -438,12 +438,7 @@ impl WireguardNetwork {
"Assigning IPs in network {} for all existing devices ",
self
);
- let all_devices =
- WireguardNetworkDevice::all_for_network(&mut *transaction, self.id).await?;
- let used_ips: HashSet = all_devices
- .into_iter()
- .flat_map(|device| device.wireguard_ips)
- .collect();
+ let used_ips = self.all_used_ips_for_network(&mut *transaction).await?;
let devices = self.get_allowed_devices(&mut *transaction).await?;
for device in devices {
device
@@ -463,13 +458,7 @@ impl WireguardNetwork {
info!("Assigning IP in network {self} for {device}");
let allowed_devices = self.get_allowed_devices(&mut *transaction).await?;
let allowed_device_ids: Vec = allowed_devices.iter().map(|dev| dev.id).collect();
-
- let all_devices =
- WireguardNetworkDevice::all_for_network(&mut *transaction, self.id).await?;
- let used_ips: HashSet = all_devices
- .into_iter()
- .flat_map(|device| device.wireguard_ips)
- .collect();
+ let used_ips = self.all_used_ips_for_network(&mut *transaction).await?;
if allowed_device_ids.contains(&device.id) {
let wireguard_network_device = device
@@ -1368,6 +1357,20 @@ impl WireguardNetwork {
.fetch_all(executor)
.await
}
+
+ /// Obtain all used ips for network
+ pub async fn all_used_ips_for_network(
+ &self,
+ transaction: &mut PgConnection,
+ ) -> Result, SqlxError> {
+ let all_devices =
+ WireguardNetworkDevice::all_for_network(&mut *transaction, self.id).await?;
+ let used_ips: HashSet = all_devices
+ .into_iter()
+ .flat_map(|device| device.wireguard_ips)
+ .collect();
+ Ok(used_ips)
+ }
}
// [`IpNetwork`] does not implement [`Default`]
diff --git a/crates/defguard_core/src/lib.rs b/crates/defguard_core/src/lib.rs
index 580dfee74..3ab970166 100644
--- a/crates/defguard_core/src/lib.rs
+++ b/crates/defguard_core/src/lib.rs
@@ -740,13 +740,10 @@ pub async fn init_dev_env(config: &DefGuardConfig) {
.await
.expect("Could not save network")
};
- let all_devices = WireguardNetworkDevice::all_for_network(&mut *transaction, network.id)
+ let used_ips = network
+ .all_used_ips_for_network(&mut *transaction)
.await
- .expect("Failed to query all devices");
- let used_ips: HashSet = all_devices
- .into_iter()
- .flat_map(|device| device.wireguard_ips)
- .collect();
+ .expect("Failed to query used ip's from database");
if Device::find_by_pubkey(
&mut *transaction,
"gQYL5eMeFDj0R+lpC7oZyIl0/sNVmQDC6ckP7husZjc=",
diff --git a/crates/defguard_core/src/location_management/mod.rs b/crates/defguard_core/src/location_management/mod.rs
index 298c29773..0c64b88ac 100644
--- a/crates/defguard_core/src/location_management/mod.rs
+++ b/crates/defguard_core/src/location_management/mod.rs
@@ -168,12 +168,7 @@ pub async fn process_device_access_changes(
// Loop through current device configurations; remove no longer allowed, readdress
// when necessary; remove processed entry from all devices list initial list should
// now contain only devices to be added.
- let all_devices =
- WireguardNetworkDevice::all_for_network(&mut *transaction, location.id).await?;
- let used_ips: HashSet = all_devices
- .into_iter()
- .flat_map(|device| device.wireguard_ips)
- .collect();
+ let used_ips = location.all_used_ips_for_network(&mut *transaction).await?;
let mut events: Vec = Vec::new();
for device_network_config in currently_configured_devices {
// Device is allowed and an IP was already assigned
@@ -227,12 +222,6 @@ pub async fn process_device_access_changes(
}
}
}
- let all_devices =
- WireguardNetworkDevice::all_for_network(&mut *transaction, location.id).await?;
- let used_ips: HashSet = all_devices
- .into_iter()
- .flat_map(|device| device.wireguard_ips)
- .collect();
// Add configs for new allowed devices
for device in allowed_devices.into_values() {
let wireguard_network_device = device
@@ -671,4 +660,103 @@ mod test {
transaction.commit().await.unwrap();
}
+
+ #[sqlx::test]
+ async fn test_readdress_on_network_change(_: PgPoolOptions, options: PgConnectOptions) {
+ use std::net::IpAddr;
+
+ let pool = setup_pool(options).await;
+
+ // Sieć z trzema podsieciami
+ let mut network = WireguardNetwork::default();
+ network
+ .try_set_address("10.0.0.1/8,12.0.0.1/8,14.0.0.1/8")
+ .unwrap();
+ let network = network.save(&pool).await.unwrap();
+
+ let user = User::new(
+ "testuser",
+ Some("pass"),
+ "Test",
+ "User",
+ "test@test.com",
+ None,
+ )
+ .save(&pool)
+ .await
+ .unwrap();
+
+ let device = Device::new(
+ "device1".into(),
+ "key1".into(),
+ user.id,
+ DeviceType::User,
+ None,
+ true,
+ )
+ .save(&pool)
+ .await
+ .unwrap();
+
+ // Ręczne przypisanie konkretnych IP do urządzenia
+ let ip_10: IpAddr = "10.0.0.10".parse().unwrap();
+ let ip_12: IpAddr = "12.0.0.12".parse().unwrap();
+ let ip_14: IpAddr = "14.0.0.15".parse().unwrap();
+
+ WireguardNetworkDevice::new(network.id, device.id, vec![ip_10, ip_12, ip_14])
+ .insert(&pool)
+ .await
+ .unwrap();
+
+ // Zmiana sieci: 12.x -> 15.x, maska 14.x zmieniona z /8 na /16
+ let mut network = network;
+ network.address = "10.0.0.1/8,15.0.0.1/8,14.0.0.1/16"
+ .split(',')
+ .map(|s| s.trim().parse::().unwrap())
+ .collect();
+
+ let mut transaction = pool.begin().await.unwrap();
+
+ let events = sync_location_allowed_devices(&network, &mut transaction, None)
+ .await
+ .unwrap();
+
+ transaction.commit().await.unwrap();
+
+ // Szukamy eventu modyfikacji dla naszego urządzenia
+ let new_ips = events
+ .iter()
+ .find_map(|e| match e {
+ GatewayEvent::DeviceModified(info) if info.device.id == device.id => {
+ Some(&info.network_info[0].device_wireguard_ips)
+ }
+ _ => None,
+ })
+ .expect("Oczekiwano zdarzenia DeviceModified dla urządzenia");
+
+ // 10.0.0.10 nadal pasuje do 10.0.0.0/8 - powinien pozostać
+ assert!(
+ new_ips.contains(&ip_10),
+ "10.0.0.10 powinno pozostać: {new_ips:?}"
+ );
+
+ // 12.0.0.12 nie pasuje do żadnej nowej podsieci - powinno zostać zastąpione przez 15.x.x.x
+ assert!(
+ !new_ips.contains(&ip_12),
+ "12.0.0.12 powinno zostać przepisane: {new_ips:?}"
+ );
+ assert!(
+ new_ips.iter().any(|ip| match ip {
+ IpAddr::V4(v4) => v4.octets()[0] == 15,
+ _ => false,
+ }),
+ "Oczekiwano adresu z zakresu 15.x.x.x: {new_ips:?}"
+ );
+
+ // 14.0.0.15 nadal pasuje do 14.0.0.0/16 - powinien pozostać
+ assert!(
+ new_ips.contains(&ip_14),
+ "14.0.0.15 powinno pozostać: {new_ips:?}"
+ );
+ }
}
diff --git a/tools/defguard_generator/src/vpn_session_stats.rs b/tools/defguard_generator/src/vpn_session_stats.rs
index a134f6b04..f9ded71e0 100644
--- a/tools/defguard_generator/src/vpn_session_stats.rs
+++ b/tools/defguard_generator/src/vpn_session_stats.rs
@@ -70,6 +70,7 @@ pub async fn generate_vpn_session_stats(
let devices =
prepare_user_devices(&pool, &mut rng, &user, config.devices_per_user as usize).await?;
+ let used_ips = location.all_used_ips_for_network(&mut *transaction).await?;
// assign devices to the network if not already assigned
for device in &devices {
if WireguardNetworkDevice::find(&mut *transaction, device.id, location.id)
@@ -81,7 +82,7 @@ pub async fn generate_vpn_session_stats(
device.name, location.name
);
device
- .assign_next_network_ip(&mut transaction, &location, None, None)
+ .assign_next_network_ip(&mut transaction, &location, &used_ips, None, None)
.await?;
} else {
info!(
From 5800ac62aae21b97b0c07aab3584f5d8e00710e2 Mon Sep 17 00:00:00 2001
From: jakub-tldr <78603704+jakub-tldr@users.noreply.github.com>
Date: Mon, 2 Mar 2026 13:43:08 +0100
Subject: [PATCH 05/11] remove spacing between networks
---
web/src/pages/EditLocationPage/EditLocationPage.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/web/src/pages/EditLocationPage/EditLocationPage.tsx b/web/src/pages/EditLocationPage/EditLocationPage.tsx
index 5bccbf85d..b81157f34 100644
--- a/web/src/pages/EditLocationPage/EditLocationPage.tsx
+++ b/web/src/pages/EditLocationPage/EditLocationPage.tsx
@@ -190,9 +190,9 @@ const EditLocationForm = ({ location }: { location: NetworkLocation }) => {
const defaultValues = useMemo(
(): FormFields => ({
name: location.name,
- address: location.address.join(', '),
+ address: location.address.join(','),
allowed_groups: location.allowed_groups,
- allowed_ips: location.allowed_ips.join(', '),
+ allowed_ips: location.allowed_ips.join(','),
dns: location.dns,
endpoint: location.endpoint,
keepalive_interval: location.keepalive_interval,
From 3b143ebf8c0526d28500353159a0ac0522c72fe7 Mon Sep 17 00:00:00 2001
From: jakub-tldr <78603704+jakub-tldr@users.noreply.github.com>
Date: Mon, 2 Mar 2026 18:19:43 +0100
Subject: [PATCH 06/11] ip reassignment test
---
.../defguard_common/src/db/models/device.rs | 259 ++++++++++++++++++
1 file changed, 259 insertions(+)
diff --git a/crates/defguard_common/src/db/models/device.rs b/crates/defguard_common/src/db/models/device.rs
index d4f1362b7..8d6134e85 100644
--- a/crates/defguard_common/src/db/models/device.rs
+++ b/crates/defguard_common/src/db/models/device.rs
@@ -1135,6 +1135,265 @@ mod test {
assert!(device.is_err());
}
+ /// Test that assign_next_network_ip correctly preserves or reassigns device IPs
+ /// when a network's address list changes.
+ /// Initial network: 10.0.0.0/8, 123.10.0.0/16, 123.123.123.0/24
+ /// Device IPs: 10.0.0.234, 123.10.33.44, 123.123.123.52
+ /// New network: 10.0.0.0/16, 123.12.0.0/16, 123.123.0.0/16
+ /// Expected:
+ /// - 10.0.0.234 KEPT (still within 10.0.0.0/16)
+ /// - 123.10.33.44 CHANGED (not within 123.12.0.0/16)
+ /// - 123.123.123.52 KEPT (still within 123.123.0.0/16)
+ #[sqlx::test]
+ async fn test_assign_next_network_ip_preserves_matching_subnets(
+ _: PgPoolOptions,
+ options: PgConnectOptions,
+ ) {
+ let pool = setup_pool(options).await;
+
+ let mut network = WireguardNetwork::default();
+ network
+ .try_set_address("10.0.0.1/8,123.10.0.1/16,123.123.123.1/24")
+ .unwrap();
+ let network = network.save(&pool).await.unwrap();
+
+ let user = User::new(
+ "testuser",
+ Some("password"),
+ "Tester",
+ "Test",
+ "test@test.com",
+ None,
+ )
+ .save(&pool)
+ .await
+ .unwrap();
+
+ let device = Device::new(
+ "dev1".into(),
+ "key1".into(),
+ user.id,
+ DeviceType::User,
+ None,
+ true,
+ )
+ .save(&pool)
+ .await
+ .unwrap();
+
+ let ip = IpAddr::from_str("10.0.0.234").unwrap();
+ let ip2 = IpAddr::from_str("123.10.33.44").unwrap();
+ let ip3 = IpAddr::from_str("123.123.123.52").unwrap();
+ let initial_ips = vec![ip, ip2, ip3];
+
+ let mut conn = pool.acquire().await.unwrap();
+ WireguardNetworkDevice::new(network.id, device.id, initial_ips.clone())
+ .insert(&mut *conn)
+ .await
+ .unwrap();
+
+ let mut updated_network = network.clone();
+ updated_network.address = vec![
+ "10.0.0.0/16".parse::().unwrap(),
+ "123.12.0.0/16".parse::().unwrap(),
+ "123.123.0.0/16".parse::().unwrap(),
+ ];
+ updated_network.save(&mut *conn).await.unwrap();
+
+ let used_ips = updated_network
+ .all_used_ips_for_network(&mut *conn)
+ .await
+ .unwrap();
+
+ let result = device
+ .assign_next_network_ip(
+ &mut *conn,
+ &updated_network,
+ &used_ips,
+ None,
+ Some(&initial_ips),
+ )
+ .await
+ .unwrap();
+
+ let new_ips = &result.wireguard_ips;
+ assert_eq!(new_ips.len(), 3, "should have one IP per subnet");
+
+ assert!(
+ new_ips.contains(&ip),
+ "10.0.0.234 should be kept – it is still within 10.0.0.0/16; got {new_ips:?}"
+ );
+
+ assert!(
+ !new_ips.contains(&ip2),
+ "123.10.33.44 should be reassigned – not within 123.12.0.0/16; got {new_ips:?}"
+ );
+ let network: IpNetwork = "123.12.0.0/16".parse().unwrap();
+ assert!(
+ new_ips.iter().any(|ip| network.contains(*ip)),
+ "a new IP within 123.12.0.0/16 should be assigned; got {new_ips:?}"
+ );
+
+ assert!(
+ new_ips.contains(&ip3),
+ "123.123.123.52 should be kept – it is still within 123.123.0.0/16; got {new_ips:?}"
+ );
+ }
+ /// Initial: 10.0.0.0/8 | 10.1.0.5
+ /// Modified: 10.0.0.0/16 | 10.1.0.5 should be replaced with a 10.0.x.x address
+ #[sqlx::test]
+ async fn test_assign_next_network_ip_subnet_narrowed(
+ _: PgPoolOptions,
+ options: PgConnectOptions,
+ ) {
+ let pool = setup_pool(options).await;
+
+ let mut network = WireguardNetwork::default();
+ network.try_set_address("10.0.0.1/8").unwrap();
+ let network = network.save(&pool).await.unwrap();
+
+ let user = User::new(
+ "testuser",
+ Some("password"),
+ "Tester",
+ "Test",
+ "test@test.com",
+ None,
+ )
+ .save(&pool)
+ .await
+ .unwrap();
+
+ let device = Device::new(
+ "dev1".into(),
+ "key1".into(),
+ user.id,
+ DeviceType::User,
+ None,
+ true,
+ )
+ .save(&pool)
+ .await
+ .unwrap();
+
+ let ip = IpAddr::from_str("10.1.0.5").unwrap();
+ let initial_ips = vec![ip];
+
+ let mut conn = pool.acquire().await.unwrap();
+ WireguardNetworkDevice::new(network.id, device.id, initial_ips.clone())
+ .insert(&mut *conn)
+ .await
+ .unwrap();
+
+ let mut updated_network = network.clone();
+ updated_network.address = vec!["10.0.0.0/16".parse::().unwrap()];
+ updated_network.save(&mut *conn).await.unwrap();
+
+ let used_ips = updated_network
+ .all_used_ips_for_network(&mut *conn)
+ .await
+ .unwrap();
+
+ let result = device
+ .assign_next_network_ip(
+ &mut *conn,
+ &updated_network,
+ &used_ips,
+ None,
+ Some(&initial_ips),
+ )
+ .await
+ .unwrap();
+
+ let new_ips = &result.wireguard_ips;
+ assert_eq!(new_ips.len(), 1, "should have one IP per subnet");
+
+ assert!(
+ !new_ips.contains(&ip),
+ "10.1.0.5 should be reassigned – outside narrowed 10.0.0.0/16; got {new_ips:?}"
+ );
+ let narrowed_net: IpNetwork = "10.0.0.0/16".parse().unwrap();
+ assert!(
+ new_ips.iter().all(|ip| narrowed_net.contains(*ip)),
+ "new IP must be within 10.0.0.0/16; got {new_ips:?}"
+ );
+ }
+
+ /// Initial: 123.123.123.0/24 | 123.123.123.254
+ /// Modified: 123.123.0.0/16 | 123.123.123.254 still fits
+ #[sqlx::test]
+ async fn test_assign_next_network_ip_still_valid_after_widening(
+ _: PgPoolOptions,
+ options: PgConnectOptions,
+ ) {
+ let pool = setup_pool(options).await;
+
+ let mut network = WireguardNetwork::default();
+ network.try_set_address("123.123.123.1/24").unwrap();
+ let network = network.save(&pool).await.unwrap();
+
+ let user = User::new(
+ "testuser",
+ Some("password"),
+ "Tester",
+ "Test",
+ "test@test.com",
+ None,
+ )
+ .save(&pool)
+ .await
+ .unwrap();
+
+ let device = Device::new(
+ "dev1".into(),
+ "key1".into(),
+ user.id,
+ DeviceType::User,
+ None,
+ true,
+ )
+ .save(&pool)
+ .await
+ .unwrap();
+
+ let ip = IpAddr::from_str("123.123.123.254").unwrap();
+ let initial_ips = vec![ip];
+
+ let mut conn = pool.acquire().await.unwrap();
+ WireguardNetworkDevice::new(network.id, device.id, initial_ips.clone())
+ .insert(&mut *conn)
+ .await
+ .unwrap();
+
+ let mut updated_network = network.clone();
+ updated_network.address = vec!["123.123.0.0/16".parse::().unwrap()];
+ updated_network.save(&mut *conn).await.unwrap();
+
+ let used_ips = updated_network
+ .all_used_ips_for_network(&mut *conn)
+ .await
+ .unwrap();
+
+ let result = device
+ .assign_next_network_ip(
+ &mut *conn,
+ &updated_network,
+ &used_ips,
+ None,
+ Some(&initial_ips),
+ )
+ .await
+ .unwrap();
+
+ let new_ips = &result.wireguard_ips;
+ assert_eq!(new_ips.len(), 1, "should have one IP per subnet");
+
+ assert!(
+ new_ips.contains(&ip),
+ "123.123.123.254 should be preserved – still within widened 123.123.0.0/16; got {new_ips:?}"
+ );
+ }
+
#[test]
fn test_pubkey_validation() {
let invalid_test_key = "invalid_key";
From c9e1f6e41d0efc1064a6a82a2ea35388b11c8dbd Mon Sep 17 00:00:00 2001
From: jakub-tldr <78603704+jakub-tldr@users.noreply.github.com>
Date: Mon, 2 Mar 2026 18:26:03 +0100
Subject: [PATCH 07/11] make clippy happy
---
.../src/db/models/wireguard.rs | 4 +-
crates/defguard_core/src/lib.rs | 4 +-
.../src/location_management/mod.rs | 104 +-----------------
3 files changed, 3 insertions(+), 109 deletions(-)
diff --git a/crates/defguard_common/src/db/models/wireguard.rs b/crates/defguard_common/src/db/models/wireguard.rs
index aed2bb593..0f687ea7f 100644
--- a/crates/defguard_common/src/db/models/wireguard.rs
+++ b/crates/defguard_common/src/db/models/wireguard.rs
@@ -536,9 +536,7 @@ impl WireguardNetwork {
// split into separate stats for each device
let mut device_stats: HashMap> =
stats.into_iter().fold(HashMap::new(), |mut acc, item| {
- acc.entry(item.device_id)
- .or_insert_with(Vec::new)
- .push(item);
+ acc.entry(item.device_id).or_default().push(item);
acc
});
diff --git a/crates/defguard_core/src/lib.rs b/crates/defguard_core/src/lib.rs
index 3ab970166..849e119b7 100644
--- a/crates/defguard_core/src/lib.rs
+++ b/crates/defguard_core/src/lib.rs
@@ -1,6 +1,5 @@
#![allow(clippy::too_many_arguments)]
use std::{
- collections::HashSet,
net::{IpAddr, Ipv4Addr, SocketAddr},
sync::{Arc, LazyLock, Mutex, RwLock},
};
@@ -21,7 +20,6 @@ use defguard_common::{
init_db,
models::{
Device, DeviceType, Settings, User, WireguardNetwork,
- device::WireguardNetworkDevice,
oauth2client::OAuth2Client,
settings::{initialize_current_settings, update_current_settings},
wireguard::{
@@ -741,7 +739,7 @@ pub async fn init_dev_env(config: &DefGuardConfig) {
.expect("Could not save network")
};
let used_ips = network
- .all_used_ips_for_network(&mut *transaction)
+ .all_used_ips_for_network(&mut transaction)
.await
.expect("Failed to query used ip's from database");
if Device::find_by_pubkey(
diff --git a/crates/defguard_core/src/location_management/mod.rs b/crates/defguard_core/src/location_management/mod.rs
index 0c64b88ac..51bac5237 100644
--- a/crates/defguard_core/src/location_management/mod.rs
+++ b/crates/defguard_core/src/location_management/mod.rs
@@ -1,7 +1,4 @@
-use std::{
- collections::{HashMap, HashSet},
- net::IpAddr,
-};
+use std::{collections::HashMap, net::IpAddr};
use defguard_common::{
csv::AsCsv,
@@ -660,103 +657,4 @@ mod test {
transaction.commit().await.unwrap();
}
-
- #[sqlx::test]
- async fn test_readdress_on_network_change(_: PgPoolOptions, options: PgConnectOptions) {
- use std::net::IpAddr;
-
- let pool = setup_pool(options).await;
-
- // Sieć z trzema podsieciami
- let mut network = WireguardNetwork::default();
- network
- .try_set_address("10.0.0.1/8,12.0.0.1/8,14.0.0.1/8")
- .unwrap();
- let network = network.save(&pool).await.unwrap();
-
- let user = User::new(
- "testuser",
- Some("pass"),
- "Test",
- "User",
- "test@test.com",
- None,
- )
- .save(&pool)
- .await
- .unwrap();
-
- let device = Device::new(
- "device1".into(),
- "key1".into(),
- user.id,
- DeviceType::User,
- None,
- true,
- )
- .save(&pool)
- .await
- .unwrap();
-
- // Ręczne przypisanie konkretnych IP do urządzenia
- let ip_10: IpAddr = "10.0.0.10".parse().unwrap();
- let ip_12: IpAddr = "12.0.0.12".parse().unwrap();
- let ip_14: IpAddr = "14.0.0.15".parse().unwrap();
-
- WireguardNetworkDevice::new(network.id, device.id, vec![ip_10, ip_12, ip_14])
- .insert(&pool)
- .await
- .unwrap();
-
- // Zmiana sieci: 12.x -> 15.x, maska 14.x zmieniona z /8 na /16
- let mut network = network;
- network.address = "10.0.0.1/8,15.0.0.1/8,14.0.0.1/16"
- .split(',')
- .map(|s| s.trim().parse::().unwrap())
- .collect();
-
- let mut transaction = pool.begin().await.unwrap();
-
- let events = sync_location_allowed_devices(&network, &mut transaction, None)
- .await
- .unwrap();
-
- transaction.commit().await.unwrap();
-
- // Szukamy eventu modyfikacji dla naszego urządzenia
- let new_ips = events
- .iter()
- .find_map(|e| match e {
- GatewayEvent::DeviceModified(info) if info.device.id == device.id => {
- Some(&info.network_info[0].device_wireguard_ips)
- }
- _ => None,
- })
- .expect("Oczekiwano zdarzenia DeviceModified dla urządzenia");
-
- // 10.0.0.10 nadal pasuje do 10.0.0.0/8 - powinien pozostać
- assert!(
- new_ips.contains(&ip_10),
- "10.0.0.10 powinno pozostać: {new_ips:?}"
- );
-
- // 12.0.0.12 nie pasuje do żadnej nowej podsieci - powinno zostać zastąpione przez 15.x.x.x
- assert!(
- !new_ips.contains(&ip_12),
- "12.0.0.12 powinno zostać przepisane: {new_ips:?}"
- );
- assert!(
- new_ips.iter().any(|ip| match ip {
- IpAddr::V4(v4) => v4.octets()[0] == 15,
- _ => false,
- }),
- "Oczekiwano adresu z zakresu 15.x.x.x: {new_ips:?}"
- );
-
- // 14.0.0.15 nadal pasuje do 14.0.0.0/16 - powinien pozostać
- assert!(
- new_ips.contains(&ip_14),
- "14.0.0.15 powinno pozostać: {new_ips:?}"
- );
- }
}
From 333cef2aa45d9b9ef4c3b2c81abcc816ad58853d Mon Sep 17 00:00:00 2001
From: jakub-tldr <78603704+jakub-tldr@users.noreply.github.com>
Date: Mon, 2 Mar 2026 18:39:59 +0100
Subject: [PATCH 08/11] remove duplicated code
---
crates/defguard_common/src/db/models/device.rs | 4 ----
1 file changed, 4 deletions(-)
diff --git a/crates/defguard_common/src/db/models/device.rs b/crates/defguard_common/src/db/models/device.rs
index 8d6134e85..52ac245ec 100644
--- a/crates/defguard_common/src/db/models/device.rs
+++ b/crates/defguard_common/src/db/models/device.rs
@@ -881,10 +881,6 @@ impl Device {
continue;
}
- if reserved.contains(&ip) {
- continue;
- }
-
picked = Some(ip);
break;
}
From 66ff71f4e811f4b314dec723b57dd2d87e615675 Mon Sep 17 00:00:00 2001
From: jakub-tldr <78603704+jakub-tldr@users.noreply.github.com>
Date: Mon, 2 Mar 2026 18:53:15 +0100
Subject: [PATCH 09/11] linter
---
web/src/pages/EditLocationPage/EditLocationPage.tsx | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/web/src/pages/EditLocationPage/EditLocationPage.tsx b/web/src/pages/EditLocationPage/EditLocationPage.tsx
index b81157f34..d32dfc683 100644
--- a/web/src/pages/EditLocationPage/EditLocationPage.tsx
+++ b/web/src/pages/EditLocationPage/EditLocationPage.tsx
@@ -267,10 +267,7 @@ const EditLocationForm = ({ location }: { location: NetworkLocation }) => {
)}
{(field) => (
-
+
)}
From ef03a97e6491b0c554706ddbf755eb63bae503cb Mon Sep 17 00:00:00 2001
From: jakub-tldr <78603704+jakub-tldr@users.noreply.github.com>
Date: Mon, 2 Mar 2026 19:01:05 +0100
Subject: [PATCH 10/11] make clippy happy 2
---
crates/defguard_common/src/db/models/device.rs | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/crates/defguard_common/src/db/models/device.rs b/crates/defguard_common/src/db/models/device.rs
index 52ac245ec..a5831c64d 100644
--- a/crates/defguard_common/src/db/models/device.rs
+++ b/crates/defguard_common/src/db/models/device.rs
@@ -1197,13 +1197,13 @@ mod test {
updated_network.save(&mut *conn).await.unwrap();
let used_ips = updated_network
- .all_used_ips_for_network(&mut *conn)
+ .all_used_ips_for_network(&mut conn)
.await
.unwrap();
let result = device
.assign_next_network_ip(
- &mut *conn,
+ &mut conn,
&updated_network,
&used_ips,
None,
@@ -1286,13 +1286,13 @@ mod test {
updated_network.save(&mut *conn).await.unwrap();
let used_ips = updated_network
- .all_used_ips_for_network(&mut *conn)
+ .all_used_ips_for_network(&mut conn)
.await
.unwrap();
let result = device
.assign_next_network_ip(
- &mut *conn,
+ &mut conn,
&updated_network,
&used_ips,
None,
@@ -1366,13 +1366,13 @@ mod test {
updated_network.save(&mut *conn).await.unwrap();
let used_ips = updated_network
- .all_used_ips_for_network(&mut *conn)
+ .all_used_ips_for_network(&mut conn)
.await
.unwrap();
let result = device
.assign_next_network_ip(
- &mut *conn,
+ &mut conn,
&updated_network,
&used_ips,
None,
From db776cde5ed961a0c4f7fb182beb2b982e157fd1 Mon Sep 17 00:00:00 2001
From: jakub-tldr <78603704+jakub-tldr@users.noreply.github.com>
Date: Mon, 2 Mar 2026 19:34:04 +0100
Subject: [PATCH 11/11] remove tests + adjust existing test
---
.../tests/integration/api/wireguard.rs | 94 +------------------
1 file changed, 2 insertions(+), 92 deletions(-)
diff --git a/crates/defguard_core/tests/integration/api/wireguard.rs b/crates/defguard_core/tests/integration/api/wireguard.rs
index ec2591b82..c29353019 100644
--- a/crates/defguard_core/tests/integration/api/wireguard.rs
+++ b/crates/defguard_core/tests/integration/api/wireguard.rs
@@ -533,7 +533,7 @@ async fn test_network_address_reassignment(_: PgPoolOptions, options: PgConnectO
vec![IpAddr::V4(Ipv4Addr::new(10, 1, 1, 3))],
);
- // trying to modify network addresses while devices exist should fail
+ // trying to modify network addresses while devices exist shouldn't fail
let network = json!({
"id": network_id,
"name": "network",
@@ -557,7 +557,7 @@ async fn test_network_address_reassignment(_: PgPoolOptions, options: PgConnectO
.json(&network)
.send()
.await;
- assert_eq!(response.status(), StatusCode::BAD_REQUEST);
+ assert_eq!(response.status(), StatusCode::OK);
// delete both devices
let response = client
@@ -571,14 +571,6 @@ async fn test_network_address_reassignment(_: PgPoolOptions, options: PgConnectO
.await;
assert_eq!(response.status(), StatusCode::OK);
- // now modify network addresses should succeed
- let response = client
- .put(format!("/api/v1/network/{network_id}"))
- .json(&network)
- .send()
- .await;
- assert_eq!(response.status(), StatusCode::OK);
-
// re-create a device and verify it gets IPs in both subnets
let device = json!({
"name": "device3",
@@ -920,85 +912,3 @@ async fn test_network_size_validation(_: PgPoolOptions, options: PgConnectOption
.await;
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
}
-
-/// Test that modifying a network's address is blocked when any devices are assigned.
-/// Also verifies that non-address modifications still succeed.
-#[sqlx::test]
-async fn test_modify_network_blocked_by_devices(_: PgPoolOptions, options: PgConnectOptions) {
- let pool = setup_pool(options).await;
-
- let (client, _client_state) = make_test_client(pool).await;
-
- let auth = Auth::new("admin", "pass123");
- let response = &client.post("/api/v1/auth").json(&auth).send().await;
- assert_eq!(response.status(), StatusCode::OK);
-
- // create network
- let response = make_network(&client, "network").await;
- let network: WireguardNetwork = response.json().await;
-
- // create a device for the admin user — it gets auto-assigned to the network
- let device = json!({
- "name": "device1",
- "wireguard_pubkey": "LQKsT6/3HWKuJmMulH63R8iK+5sI8FyYEL6WDIi6lQU=",
- });
- let response = client
- .post("/api/v1/device/admin")
- .json(&device)
- .send()
- .await;
- assert_eq!(response.status(), StatusCode::CREATED);
-
- // try to modify the network address — should be rejected because a device exists
- let modified = json!({
- "name": "network",
- "address": "10.2.2.1/24",
- "port": 55555,
- "endpoint": "192.168.4.14",
- "allowed_ips": "10.2.2.0/24",
- "dns": "1.1.1.1",
- "mtu": 1420,
- "fwmark": 0,
- "allowed_groups": [],
- "keepalive_interval": 25,
- "peer_disconnect_threshold": 300,
- "acl_enabled": false,
- "acl_default_allow": false,
- "location_mfa_mode": "disabled",
- "service_location_mode": "disabled"
- });
- let response = client
- .put(format!("/api/v1/network/{}", network.id))
- .json(&modified)
- .send()
- .await;
- assert_eq!(response.status(), StatusCode::BAD_REQUEST);
-
- let body: serde_json::Value = response.json().await;
- assert!(body["msg"].as_str().is_some());
-
- // verify that modifying other fields (not address) still works
- let modified_name_only = json!({
- "name": "renamed-network",
- "address": "10.1.1.1/24",
- "port": 55555,
- "endpoint": "192.168.4.14",
- "allowed_ips": "10.1.1.0/24",
- "dns": "1.1.1.1",
- "mtu": 1420,
- "fwmark": 0,
- "allowed_groups": [],
- "keepalive_interval": 25,
- "peer_disconnect_threshold": 300,
- "acl_enabled": false,
- "acl_default_allow": false,
- "location_mfa_mode": "disabled",
- "service_location_mode": "disabled"
- });
- let response = client
- .put(format!("/api/v1/network/{}", network.id))
- .json(&modified_name_only)
- .send()
- .await;
- assert_eq!(response.status(), StatusCode::OK);
-}