| Crates.io | nmrs |
| lib.rs | nmrs |
| version | 2.0.0 |
| created_at | 2025-12-12 04:11:19.785969+00 |
| updated_at | 2026-01-19 16:19:42.034286+00 |
| description | A Rust library for NetworkManager over D-Bus |
| homepage | |
| repository | https://github.com/cachebag/nmrs |
| max_upload_size | |
| id | 1980965 |
| size | 511,942 |
Rust bindings for NetworkManager via D-Bus.
nmrs provides a high-level, async API for managing Wi-Fi connections on Linux systems. It abstracts the complexity of D-Bus communication with NetworkManager, offering typed error handling and an ergonomic interface.
zbus with async/await throughout[dependencies]
nmrs = "2.0.0"
or
cargo add nmrs
Below are a few examples of the different ways to interface with things like WiFi (wireless) devices, WireGuard VPN configs, or EAP connections.
use nmrs::{NetworkManager, WifiSecurity};
#[tokio::main]
async fn main() -> nmrs::Result<()> {
let nm = NetworkManager::new().await?;
// List networks
let networks = nm.list_networks().await?;
for net in &networks {
println!("{} - Signal: {}%", net.ssid, net.strength.unwrap_or(0));
}
// Connect to WPA-PSK network
nm.connect("MyNetwork", WifiSecurity::WpaPsk {
psk: "password".into()
}).await?;
// Check current connection
if let Some(ssid) = nm.current_ssid().await {
println!("Connected to: {}", ssid);
}
Ok(())
}
use nmrs::{NetworkManager, VpnCredentials, VpnType, WireGuardPeer};
#[tokio::main]
async fn main() -> nmrs::Result<()> {
let nm = NetworkManager::new().await?;
let creds = VpnCredentials {
vpn_type: VpnType::WireGuard,
name: "WorkVPN".into(),
gateway: "vpn.example.com:51820".into(),
private_key: "your_private_key_here".into(),
address: "10.0.0.2/24".into(),
peers: vec![WireGuardPeer {
public_key: "server_public_key".into(),
gateway: "vpn.example.com:51820".into(),
allowed_ips: vec!["0.0.0.0/0".into()],
preshared_key: None,
persistent_keepalive: Some(25),
}],
dns: Some(vec!["1.1.1.1".into()]),
mtu: None,
uuid: None,
};
// Connect to VPN
nm.connect_vpn(creds).await?;
// Get connection details
let info = nm.get_vpn_info("WorkVPN").await?;
println!("VPN IP: {:?}", info.ip4_address);
// Disconnect
nm.disconnect_vpn("WorkVPN").await?;
Ok(())
}
use nmrs::{NetworkManager, WifiSecurity, EapOptions, EapMethod, Phase2};
#[tokio::main]
async fn main() -> nmrs::Result<()> {
let nm = NetworkManager::new().await?;
nm.connect("CorpNetwork", WifiSecurity::WpaEap {
opts: EapOptions {
identity: "user@company.com".into(),
password: "password".into(),
anonymous_identity: None,
domain_suffix_match: Some("company.com".into()),
ca_cert_path: None,
system_ca_certs: true,
method: EapMethod::Peap,
phase2: Phase2::Mschapv2,
}
}).await?;
Ok(())
}
We also handle agnostic device management, as many of the devicees supported by NetworkManager can queried in similar ways.
use nmrs::NetworkManager;
#[tokio::main]
async fn main() -> nmrs::Result<()> {
let nm = NetworkManager::new().await?;
// List all network devices
let devices = nm.list_devices().await?;
for device in devices {
println!("{}: {} ({})", device.interface, device.device_type, device.state);
}
// Control WiFi radio
nm.set_wifi_enabled(false).await?;
nm.set_wifi_enabled(true).await?;
Ok(())
}
use nmrs::NetworkManager;
#[tokio::main]
async fn main() -> nmrs::Result<()> {
let nm = NetworkManager::new().await?;
// Monitor network changes
nm.monitor_network_changes(|| {
println!("Network list changed");
}).await?;
Ok(())
}
All operations return Result<T, ConnectionError> with specific variants:
use nmrs::{NetworkManager, WifiSecurity, ConnectionError};
match nm.connect("MyNetwork", WifiSecurity::WpaPsk {
psk: "wrong".into()
}).await {
Ok(_) => println!("Connected"),
Err(ConnectionError::AuthFailed) => eprintln!("Authentication failed"),
Err(ConnectionError::NotFound) => eprintln!("Network not in range"),
Err(ConnectionError::Timeout) => eprintln!("Connection timed out"),
Err(ConnectionError::DhcpFailed) => eprintln!("Failed to obtain IP address"),
Err(e) => eprintln!("Error: {}", e),
}
nmrs is runtime-agnostic and works with any async runtime:
async/awaitAll examples use Tokio, but you can use your preferred runtime:
With Tokio:
#[tokio::main]
async fn main() -> nmrs::Result<()> {
let nm = nmrs::NetworkManager::new().await?;
// ...
Ok(())
}
With async-std:
#[async_std::main]
async fn main() -> nmrs::Result<()> {
let nm = nmrs::NetworkManager::new().await?;
// ...
Ok(())
}
With smol:
fn main() -> nmrs::Result<()> {
smol::block_on(async {
let nm = nmrs::NetworkManager::new().await?;
// ...
Ok(())
})
}
nmrs uses zbus for D-Bus communication, which launches a background thread to handle D-Bus message processing. This design ensures compatibility across all async runtimes without requiring manual executor management.
Complete API documentation: docs.rs/nmrs
Enable logging via the log crate:
env_logger::init();
Set RUST_LOG=nmrs=debug for detailed logs.
MIT