[PATCH proxmox v3 6/8] wireguard: init configuration support crate

Christoph Heiss
2026-03-30T18:29:55Z

This introduces a new crate, `proxmox-wireguard`.

It provides:
- a slight abstraction over raw ED25519 keys and keyspairs, as used by
WireGuard
- keypair generation
- wg(8) configuration support, by providing the necessary structs and
INI serialization thereof

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
Changes v2 -> v3:
* adapt to INI serializer now living in the `proxmox-ini` crate
* fix wrong vcs url in debcargo.toml

Changes v1 -> v2:
* implement `AsRef<{Private,Preshared}Key>` instead of .raw() method
* scope key generation (and thus proxmox-sys usage) behind a feature
flag, makes it possible to use this crate in e.g. wasm context
* expand test cases a bit

Cargo.toml | 2 +
proxmox-wireguard/Cargo.toml | 26 ++
proxmox-wireguard/debian/changelog | 5 +
proxmox-wireguard/debian/control | 67 +++++
proxmox-wireguard/debian/copyright | 18 ++
proxmox-wireguard/debian/debcargo.toml | 7 +
proxmox-wireguard/src/lib.rs | 391 +++++++++++++++++++++++++
7 files changed, 516 insertions(+)
create mode 100644 proxmox-wireguard/Cargo.toml
create mode 100644 proxmox-wireguard/debian/changelog
create mode 100644 proxmox-wireguard/debian/control
create mode 100644 proxmox-wireguard/debian/copyright
create mode 100644 proxmox-wireguard/debian/debcargo.toml
create mode 100644 proxmox-wireguard/src/lib.rs

diff --git a/Cargo.toml b/Cargo.toml
index 4617bbab..735b31e6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -62,6 +62,7 @@ members = [
"proxmox-time-api",
"proxmox-upgrade-checks",
"proxmox-uuid",
+ "proxmox-wireguard",
"proxmox-worker-task",
"pbs-api-types",
"pve-api-types",
@@ -161,6 +162,7 @@ proxmox-fixed-string = { version = "0.1.0", path = "proxmox-fixed-string" }
proxmox-http = { version = "1.0.5", path = "proxmox-http" }
proxmox-http-error = { version = "1.0.0", path = "proxmox-http-error" }
proxmox-human-byte = { version = "1.0.0", path = "proxmox-human-byte" }
+proxmox-ini = { version = "0.1.0", path = "proxmox-ini" }
proxmox-io = { version = "1.2.1", path = "proxmox-io" }
proxmox-lang = { version = "1.5", path = "proxmox-lang" }
proxmox-log = { version = "1.0.0", path = "proxmox-log" }
diff --git a/proxmox-wireguard/Cargo.toml b/proxmox-wireguard/Cargo.toml
new file mode 100644
index 00000000..f11346d6
--- /dev/null
+++ b/proxmox-wireguard/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "proxmox-wireguard"
+description = "WireGuard configuration support"
+version = "0.1.0"
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+homepage.workspace = true
+exclude.workspace = true
+rust-version.workspace = true
+
+[dependencies]
+ed25519-dalek = "2.1"
+serde = { workspace = true, features = [ "derive" ] }
+thiserror.workspace = true
+proxmox-ini.workspace = true
+proxmox-network-types.workspace = true
+proxmox-sys = { workspace = true, optional = true }
+proxmox-serde.workspace = true
+
+[dev-dependencies]
+pretty_assertions.workspace = true
+
+[features]
+default = ["key-generation"]
+key-generation = ["dep:proxmox-sys"]
diff --git a/proxmox-wireguard/debian/changelog b/proxmox-wireguard/debian/changelog
new file mode 100644
index 00000000..67500279
--- /dev/null
+++ b/proxmox-wireguard/debian/changelog
@@ -0,0 +1,5 @@
+rust-proxmox-wireguard (0.1.0-1) unstable; urgency=medium
+
+ * Initial release.
+
+ -- Proxmox Support Team <support@proxmox.com> Fri, 13 Feb 2026 15:10:12 +0200
diff --git a/proxmox-wireguard/debian/control b/proxmox-wireguard/debian/control
new file mode 100644
index 00000000..1e3392ef
--- /dev/null
+++ b/proxmox-wireguard/debian/control
@@ -0,0 +1,67 @@
+Source: rust-proxmox-wireguard
+Section: rust
+Priority: optional
+Build-Depends: debhelper-compat (= 13),
+ dh-sequence-cargo
+Build-Depends-Arch: cargo:native <!nocheck>,
+ rustc:native (>= 1.85) <!nocheck>,
+ libstd-rust-dev <!nocheck>,
+ librust-ed25519-dalek-2+default-dev (>= 2.1-~~) <!nocheck>,
+ librust-proxmox-ini-0.1+default-dev <!nocheck>,
+ librust-proxmox-network-types-1+default-dev <!nocheck>,
+ librust-proxmox-serde-1+default-dev <!nocheck>,
+ librust-proxmox-serde-1+serde-json-dev <!nocheck>,
+ librust-proxmox-sys-1+default-dev (>= 1.0.1-~~) <!nocheck>,
+ librust-serde-1+default-dev <!nocheck>,
+ librust-serde-1+derive-dev <!nocheck>,
+ librust-thiserror-2+default-dev <!nocheck>
+Maintainer: Proxmox Support Team <support@proxmox.com>
+Standards-Version: 4.7.2
+Vcs-Git: git://git.proxmox.com/git/proxmox.git
+Vcs-Browser: https://git.proxmox.com/?p=proxmox.git
+Homepage: https://proxmox.com
+X-Cargo-Crate: proxmox-wireguard
+
+Package: librust-proxmox-wireguard-dev
+Architecture: any
+Multi-Arch: same
+Depends:
+ ${misc:Depends},
+ librust-ed25519-dalek-2+default-dev (>= 2.1-~~),
+ librust-proxmox-ini-0.1+default-dev,
+ librust-proxmox-network-types-1+default-dev,
+ librust-proxmox-serde-1+default-dev,
+ librust-proxmox-serde-1+serde-json-dev,
+ librust-serde-1+default-dev,
+ librust-serde-1+derive-dev,
+ librust-thiserror-2+default-dev
+Recommends:
+ librust-proxmox-wireguard+key-generation-dev (= ${binary:Version})
+Provides:
+ librust-proxmox-wireguard-0-dev (= ${binary:Version}),
+ librust-proxmox-wireguard-0.1-dev (= ${binary:Version}),
+ librust-proxmox-wireguard-0.1.0-dev (= ${binary:Version})
+Description: WireGuard configuration support - Rust source code
+ Source code for Debianized Rust crate "proxmox-wireguard"
+
+Package: librust-proxmox-wireguard+key-generation-dev
+Architecture: any
+Multi-Arch: same
+Depends:
+ ${misc:Depends},
+ librust-proxmox-wireguard-dev (= ${binary:Version}),
+ librust-proxmox-sys-1+default-dev (>= 1.0.1-~~)
+Provides:
+ librust-proxmox-wireguard+default-dev (= ${binary:Version}),
+ librust-proxmox-wireguard-0+key-generation-dev (= ${binary:Version}),
+ librust-proxmox-wireguard-0+default-dev (= ${binary:Version}),
+ librust-proxmox-wireguard-0.1+key-generation-dev (= ${binary:Version}),
+ librust-proxmox-wireguard-0.1+default-dev (= ${binary:Version}),
+ librust-proxmox-wireguard-0.1.0+key-generation-dev (= ${binary:Version}),
+ librust-proxmox-wireguard-0.1.0+default-dev (= ${binary:Version})
+Description: WireGuard configuration support - feature "key-generation" and 1 more
+ This metapackage enables feature "key-generation" for the Rust proxmox-
+ wireguard crate, by pulling in any additional dependencies needed by that
+ feature.
+ .
+ Additionally, this package also provides the "default" feature.
diff --git a/proxmox-wireguard/debian/copyright b/proxmox-wireguard/debian/copyright
new file mode 100644
index 00000000..1ea8a56b
--- /dev/null
+++ b/proxmox-wireguard/debian/copyright
@@ -0,0 +1,18 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+
+Files:
+ *
+Copyright: 2019 - 2025 Proxmox Server Solutions GmbH <support@proxmox.com>
+License: AGPL-3.0-or-later
+ This program is free software: you can redistribute it and/or modify it under
+ the terms of the GNU Affero General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option) any
+ later version.
+ .
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+ details.
+ .
+ You should have received a copy of the GNU Affero General Public License along
+ with this program. If not, see <https://www.gnu.org/licenses/>.
diff --git a/proxmox-wireguard/debian/debcargo.toml b/proxmox-wireguard/debian/debcargo.toml
new file mode 100644
index 00000000..b7864cdb
--- /dev/null
+++ b/proxmox-wireguard/debian/debcargo.toml
@@ -0,0 +1,7 @@
+overlay = "."
+crate_src_path = ".."
+maintainer = "Proxmox Support Team <support@proxmox.com>"
+
+[source]
+vcs_git = "git://git.proxmox.com/git/proxmox.git"
+vcs_browser = "https://git.proxmox.com/?p=proxmox.git"
diff --git a/proxmox-wireguard/src/lib.rs b/proxmox-wireguard/src/lib.rs
new file mode 100644
index 00000000..1712b834
--- /dev/null
+++ b/proxmox-wireguard/src/lib.rs
@@ -0,0 +1,391 @@
+//! Implements a interface for handling WireGuard configurations and serializing them into the
+//! INI-style format as described in wg(8) "CONFIGURATION FILE FORMAT".
+//!
+//! WireGuard keys are 32-bytes securely-generated values, encoded as base64
+//! for any usage where users might come in contact with them.
+//!
+//! [`PrivateKey`], [`PublicKey`] and [`PresharedKey`] implement all the needed
+//! key primitives.
+//!
+//! By design there is no key pair, as keys should be treated as opaque from a
+//! configuration perspective and not worked with.
+
+#![forbid(unsafe_code, missing_docs)]
+
+use ed25519_dalek::SigningKey;
+use serde::{Deserialize, Serialize};
+use std::fmt;
+
+use proxmox_network_types::{endpoint::ServiceEndpoint, ip_address::Cidr};
+
+/// Possible error when handling WireGuard configurations.
+#[derive(thiserror::Error, Debug, PartialEq, Clone)]
+pub enum Error {
+ /// (Private) key generation failed
+ #[error("failed to generate private key: {0}")]
+ KeyGenFailed(String),
+ /// Serialization to the WireGuard INI format failed
+ #[error("failed to serialize config: {0}")]
+ SerializationFailed(String),
+}
+
+impl From<proxmox_ini::Error> for Error {
+ fn from(err: proxmox_ini::Error) -> Self {
+ Self::SerializationFailed(err.to_string())
+ }
+}
+
+/// Public key of a WireGuard peer.
+#[derive(Clone, Copy, Deserialize, Serialize, Hash, Debug)]
+#[serde(transparent)]
+pub struct PublicKey(
+ #[serde(with = "proxmox_serde::byte_array_as_base64")] [u8; ed25519_dalek::PUBLIC_KEY_LENGTH],
+);
+
+/// Private key of a WireGuard peer.
+#[derive(Serialize)]
+#[serde(transparent)]
+pub struct PrivateKey(
+ #[serde(with = "proxmox_serde::byte_array_as_base64")] ed25519_dalek::SecretKey,
+);
+
+impl fmt::Debug for PrivateKey {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "<private-key>")
+ }
+}
+
+impl PrivateKey {
+ /// Length of the raw private key data in bytes.
+ pub const RAW_LENGTH: usize = ed25519_dalek::SECRET_KEY_LENGTH;
+
+ /// Generates a new private key suitable for use with WireGuard.
+ #[cfg(feature = "key-generation")]
+ pub fn generate() -> Result<Self, Error> {
+ generate_key().map(Self)
+ }
+
+ /// Calculates the public key from the private key.
+ pub fn public_key(&self) -> PublicKey {
+ PublicKey(
+ ed25519_dalek::SigningKey::from_bytes(&self.0)
+ .verifying_key()
+ .to_bytes(),
+ )
+ }
+
+ /// Builds a new [`PrivateKey`] from raw key material.
+ #[must_use]
+ pub fn from_raw(data: ed25519_dalek::SecretKey) -> Self {
+ // [`SigningKey`] takes care of correct key clamping.
+ Self(SigningKey::from(&data).to_bytes())
+ }
+}
+
+impl From<ed25519_dalek::SecretKey> for PrivateKey {
+ fn from(value: ed25519_dalek::SecretKey) -> Self {
+ Self(value)
+ }
+}
+
+impl AsRef<ed25519_dalek::SecretKey> for PrivateKey {
+ /// Returns the raw private key material.
+ fn as_ref(&self) -> &ed25519_dalek::SecretKey {
+ &self.0
+ }
+}
+
+/// Preshared key between two WireGuard peers.
+#[derive(Clone, Deserialize, Serialize)]
+#[serde(transparent)]
+pub struct PresharedKey(
+ #[serde(with = "proxmox_serde::byte_array_as_base64")] ed25519_dalek::SecretKey,
+);
+
+impl fmt::Debug for PresharedKey {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "<preshared-key>")
+ }
+}
+
+impl PresharedKey {
+ /// Length of the raw private key data in bytes.
+ pub const RAW_LENGTH: usize = ed25519_dalek::SECRET_KEY_LENGTH;
+
+ /// Generates a new preshared key suitable for use with WireGuard.
+ #[cfg(feature = "key-generation")]
+ pub fn generate() -> Result<Self, Error> {
+ generate_key().map(Self)
+ }
+
+ /// Builds a new [`PrivateKey`] from raw key material.
+ #[must_use]
+ pub fn from_raw(data: ed25519_dalek::SecretKey) -> Self {
+ // [`SigningKey`] takes care of correct key clamping.
+ Self(SigningKey::from(&data).to_bytes())
+ }
+}
+
+impl AsRef<ed25519_dalek::SecretKey> for PresharedKey {
+ /// Returns the raw preshared key material.
+ fn as_ref(&self) -> &ed25519_dalek::SecretKey {
+ &self.0
+ }
+}
+
+/// A single WireGuard peer.
+#[derive(Serialize, Debug)]
+#[serde(rename_all = "PascalCase")]
+pub struct WireGuardPeer {
+ /// Public key, matching the private key of of the remote peer.
+ pub public_key: PublicKey,
+ /// Additional key preshared between two peers. Adds an additional layer of symmetric-key
+ /// cryptography to be mixed into the already existing public-key cryptography, for
+ /// post-quantum resistance.
+ pub preshared_key: PresharedKey,
+ /// List of IPv4/v6 CIDRs from which incoming traffic for this peer is allowed and to which
+ /// outgoing traffic for this peer is directed. The catch-all 0.0.0.0/0 may be specified for
+ /// matching all IPv4 addresses, and ::/0 may be specified for matching all IPv6 addresses.
+ #[serde(rename = "AllowedIPs", skip_serializing_if = "Vec::is_empty")]
+ pub allowed_ips: Vec<Cidr>,
+ /// Remote peer endpoint address to connect to. Optional; only needed on the connecting side.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub endpoint: Option<ServiceEndpoint>,
+ /// A seconds interval, between 1 and 65535 inclusive, of how often to send an authenticated
+ /// empty packet to the peer for the purpose of keeping a stateful firewall or NAT mapping
+ /// valid persistently. For example, if the interface very rarely sends traffic, but it might
+ /// at anytime receive traffic from a peer, and it is behind NAT, the interface might benefit
+ /// from having a persistent keepalive interval of 25 seconds. If unset or set to 0, it is
+ /// turned off.
+ #[serde(skip_serializing_if = "persistent_keepalive_is_off")]
+ pub persistent_keepalive: Option<u16>,
+}
+
+/// Determines whether the given `PersistentKeepalive` value means that it is
+/// turned off. Useful for usage with serde's `skip_serializing_if`.
+fn persistent_keepalive_is_off(value: &Option<u16>) -> bool {
+ value.map(|v| v == 0).unwrap_or(true)
+}
+
+/// Properties of a WireGuard interface.
+#[derive(Serialize, Debug)]
+#[serde(rename_all = "PascalCase")]
+pub struct WireGuardInterface {
+ /// Private key for this interface.
+ pub private_key: PrivateKey,
+ /// Port to listen on. Optional; if not specified, chosen randomly. Only needed on the "server"
+ /// side.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub listen_port: Option<u16>,
+ /// Fwmark for outgoing packets.
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub fw_mark: Option<u32>,
+}
+
+/// Top-level WireGuard configuration for WireGuard network interface. Holds all
+/// parameters for the interface itself, as well as its remote peers.
+#[derive(Serialize, Debug)]
+#[serde(rename_all = "PascalCase")]
+pub struct WireGuardConfig {
+ /// The WireGuard-specific network interface configuration.
+ pub interface: WireGuardInterface,
+ /// Peers for this WireGuard interface.
+ #[serde(rename = "Peer")]
+ pub peers: Vec<WireGuardPeer>,
+}
+
+impl WireGuardConfig {
+ /// Generate a raw, INI-style configuration file as accepted by wg(8).
+ pub fn to_raw_config(self) -> Result<String, Error> {
+ Ok(proxmox_ini::to_string(&self)?)
+ }
+}
+
+/// Generates a new ED25519 private key.
+#[cfg(feature = "key-generation")]
+fn generate_key() -> Result<ed25519_dalek::SecretKey, Error> {
+ let mut secret = ed25519_dalek::SecretKey::default();
+ proxmox_sys::linux::fill_with_random_data(&mut secret)
+ .map_err(|err| Error::KeyGenFailed(err.to_string()))?;
+
+ // [`SigningKey`] takes care of correct key clamping.
+ Ok(SigningKey::from(&secret).to_bytes())
+}
+
+#[cfg(test)]
+mod tests {
+ use std::net::Ipv4Addr;
+
+ use proxmox_network_types::ip_address::Cidr;
+
+ use crate::{PresharedKey, PrivateKey, WireGuardConfig, WireGuardInterface, WireGuardPeer};
+
+ fn mock_private_key(v: u8) -> PrivateKey {
+ let base = v * 32;
+ PrivateKey((base..base + 32).collect::<Vec<u8>>().try_into().unwrap())
+ }
+
+ fn mock_preshared_key(v: u8) -> PresharedKey {
+ let base = v * 32;
+ PresharedKey((base..base + 32).collect::<Vec<u8>>().try_into().unwrap())
+ }
+
+ #[test]
+ fn single_peer() {
+ let config = WireGuardConfig {
+ interface: WireGuardInterface {
+ private_key: mock_private_key(0),
+ listen_port: Some(51820),
+ fw_mark: Some(127),
+ },
+ peers: vec![WireGuardPeer {
+ public_key: mock_private_key(1).public_key(),
+ preshared_key: mock_preshared_key(1),
+ allowed_ips: vec![Cidr::new_v4(Ipv4Addr::new(192, 168, 0, 0), 24).unwrap()],
+ endpoint: Some("foo.example.com:51820".parse().unwrap()),
+ persistent_keepalive: Some(25),
+ }],
+ };
+
+ pretty_assertions::assert_eq!(
+ config.to_raw_config().unwrap(),
+ "[Interface]
+PrivateKey = AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=
+ListenPort = 51820
+FwMark = 127
+
+[Peer]
+PublicKey = Kay64UG8yvCyLhqU000LxzYeUm0L/hLIl5S8kyKWbdc=
+PresharedKey = ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
+AllowedIPs = 192.168.0.0/24
+Endpoint = foo.example.com:51820
+PersistentKeepalive = 25
+"
+ );
+ }
+
+ #[test]
+ fn multiple_peers() {
+ let config = WireGuardConfig {
+ interface: WireGuardInterface {
+ private_key: mock_private_key(0),
+ listen_port: Some(51820),
+ fw_mark: None,
+ },
+ peers: vec![
+ WireGuardPeer {
+ public_key: mock_private_key(1).public_key(),
+ preshared_key: mock_preshared_key(1),
+ allowed_ips: vec![Cidr::new_v4(Ipv4Addr::new(192, 168, 0, 0), 24).unwrap()],
+ endpoint: Some("foo.example.com:51820".parse().unwrap()),
+ persistent_keepalive: None,
+ },
+ WireGuardPeer {
+ public_key: mock_private_key(2).public_key(),
+ preshared_key: mock_preshared_key(2),
+ allowed_ips: vec![Cidr::new_v4(Ipv4Addr::new(192, 168, 1, 0), 24).unwrap()],
+ endpoint: None,
+ persistent_keepalive: Some(25),
+ },
+ WireGuardPeer {
+ public_key: mock_private_key(3).public_key(),
+ preshared_key: mock_preshared_key(3),
+ allowed_ips: vec![Cidr::new_v4(Ipv4Addr::new(192, 168, 2, 0), 24).unwrap()],
+ endpoint: None,
+ persistent_keepalive: None,
+ },
+ WireGuardPeer {
+ public_key: mock_private_key(4).public_key(),
+ preshared_key: mock_preshared_key(4),
+ allowed_ips: vec![],
+ endpoint: Some("10.0.0.1:51820".parse().unwrap()),
+ persistent_keepalive: Some(25),
+ },
+ ],
+ };
+
+ pretty_assertions::assert_eq!(
+ config.to_raw_config().unwrap(),
+ "[Interface]
+PrivateKey = AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=
+ListenPort = 51820
+
+[Peer]
+PublicKey = Kay64UG8yvCyLhqU000LxzYeUm0L/hLIl5S8kyKWbdc=
+PresharedKey = ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
+AllowedIPs = 192.168.0.0/24
+Endpoint = foo.example.com:51820
+
+[Peer]
+PublicKey = JUO5L/EJVRFHatyDadtt3JM2ZaEZeN2hQE7hBmypVZ0=
+PresharedKey = QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl8=
+AllowedIPs = 192.168.1.0/24
+PersistentKeepalive = 25
+
+[Peer]
+PublicKey = F0VTtFbd38aQjsqxwQH+arIeK6oGF3lbfUOmNIKZP9U=
+PresharedKey = YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=
+AllowedIPs = 192.168.2.0/24
+
+[Peer]
+PublicKey = zRSzf5VulTGU/3+3Oz2B3MVh1hp1OAlLfD4aZD7l86o=
+PresharedKey = gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp8=
+Endpoint = 10.0.0.1:51820
+PersistentKeepalive = 25
+"
+ );
+ }
+
+ #[test]
+ fn non_listening_peer() {
+ let config = WireGuardConfig {
+ interface: WireGuardInterface {
+ private_key: mock_private_key(0),
+ listen_port: None,
+ fw_mark: None,
+ },
+ peers: vec![WireGuardPeer {
+ public_key: mock_private_key(1).public_key(),
+ preshared_key: mock_preshared_key(1),
+ allowed_ips: vec![Cidr::new_v4(Ipv4Addr::new(192, 168, 0, 0), 24).unwrap()],
+ endpoint: Some("10.0.0.1:51820".parse().unwrap()),
+ persistent_keepalive: Some(25),
+ }],
+ };
+
+ pretty_assertions::assert_eq!(
+ config.to_raw_config().unwrap(),
+ "[Interface]
+PrivateKey = AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=
+
+[Peer]
+PublicKey = Kay64UG8yvCyLhqU000LxzYeUm0L/hLIl5S8kyKWbdc=
+PresharedKey = ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
+AllowedIPs = 192.168.0.0/24
+Endpoint = 10.0.0.1:51820
+PersistentKeepalive = 25
+"
+ );
+ }
+
+ #[test]
+ fn empty_peers() {
+ let config = WireGuardConfig {
+ interface: WireGuardInterface {
+ private_key: mock_private_key(0),
+ listen_port: Some(51830),
+ fw_mark: Some(240),
+ },
+ peers: vec![],
+ };
+
+ pretty_assertions::assert_eq!(
+ config.to_raw_config().unwrap(),
+ "[Interface]
+PrivateKey = AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=
+ListenPort = 51830
+FwMark = 240
+"
+ );
+ }
+}
--
2.53.0