nmrs/lib.rs
1//! A Rust library for managing network connections via NetworkManager.
2//!
3//! This crate provides a high-level async API for NetworkManager over D-Bus,
4//! enabling easy management of WiFi, Ethernet, and VPN connections on Linux.
5//!
6//! # Quick Start
7//!
8//! ## WiFi Connection
9//!
10//! ```rust
11//! use nmrs::{NetworkManager, WifiSecurity};
12//!
13//! # async fn example() -> nmrs::Result<()> {
14//! let nm = NetworkManager::new().await?;
15//!
16//! // List visible networks (None = all Wi-Fi devices)
17//! let networks = nm.list_networks(None).await?;
18//! for net in &networks {
19//! println!("{} - Signal: {}%", net.ssid, net.strength.unwrap_or(0));
20//! }
21//!
22//! // Connect to a network on the first Wi-Fi device
23//! nm.connect("MyNetwork", None, WifiSecurity::WpaPsk {
24//! psk: "password123".into()
25//! }).await?;
26//!
27//! // Check current connection
28//! if let Some(ssid) = nm.current_ssid().await {
29//! println!("Connected to: {}", ssid);
30//! }
31//! # Ok(())
32//! # }
33//! ```
34//!
35//! ## VPN Connection (WireGuard)
36//!
37//! ```rust
38//! use nmrs::{NetworkManager, WireGuardConfig, WireGuardPeer};
39//!
40//! # async fn example() -> nmrs::Result<()> {
41//! let nm = NetworkManager::new().await?;
42//!
43//! let peer = WireGuardPeer::new(
44//! "peer_public_key",
45//! "vpn.example.com:51820",
46//! vec!["0.0.0.0/0".into()],
47//! ).with_persistent_keepalive(25);
48//!
49//! let config = WireGuardConfig::new(
50//! "MyVPN",
51//! "vpn.example.com:51820",
52//! "your_private_key",
53//! "10.0.0.2/24",
54//! vec![peer],
55//! ).with_dns(vec!["1.1.1.1".into(), "8.8.8.8".into()]);
56//!
57//! nm.connect_vpn(config).await?;
58//! # Ok(())
59//! # }
60//! ```
61//!
62//! ## VPN Connection (OpenVPN)
63//!
64//! ```rust
65//! use nmrs::{NetworkManager, OpenVpnConfig, OpenVpnAuthType};
66//!
67//! # async fn example() -> nmrs::Result<()> {
68//! let nm = NetworkManager::new().await?;
69//!
70//! let config = OpenVpnConfig::new("CorpVPN", "vpn.example.com", 1194, false)
71//! .with_auth_type(OpenVpnAuthType::PasswordTls)
72//! .with_username("user")
73//! .with_password("secret")
74//! .with_ca_cert("/etc/openvpn/ca.crt")
75//! .with_client_cert("/etc/openvpn/client.crt")
76//! .with_client_key("/etc/openvpn/client.key");
77//!
78//! nm.connect_vpn(config).await?;
79//!
80//! // Or import an .ovpn file directly:
81//! nm.import_ovpn("corp.ovpn", Some("user"), Some("secret")).await?;
82//!
83//! // List VPN connections
84//! let vpns = nm.list_vpn_connections().await?;
85//! for vpn in vpns {
86//! println!("{}: {:?} - {:?}", vpn.name, vpn.vpn_type, vpn.state);
87//! }
88//!
89//! nm.disconnect_vpn("CorpVPN").await?;
90//! # Ok(())
91//! # }
92//! ```
93//!
94//! # Core Concepts
95//!
96//! ## NetworkManager
97//!
98//! The main entry point is [`NetworkManager`], which provides methods for:
99//! - Listing and managing network devices
100//! - Scanning for available Wi-Fi networks
101//! - Connecting to networks (Wi-Fi, Ethernet, Bluetooth PAN, VPN)
102//! - Managing saved connection profiles
103//! - Real-time monitoring of network and device changes
104//! - Querying connectivity state and captive-portal URLs
105//! - Toggling Wi-Fi/WWAN/Bluetooth radios and airplane mode
106//!
107//! ## Models
108//!
109//! The [`models`] module contains all types, enums, and errors. The most
110//! commonly used items are also re-exported at the crate root:
111//!
112//! - [`Device`] / [`DeviceType`] / [`DeviceState`] — network devices and their state
113//! - [`Network`] / [`AccessPoint`] / [`NetworkInfo`] — discovered Wi-Fi data
114//! - [`WifiDevice`] — per-Wi-Fi-device summary
115//! - [`WifiSecurity`] / [`EapOptions`] / [`EapMethod`] / [`Phase2`] — Wi-Fi security
116//! - [`ConnectionOptions`] / [`TimeoutConfig`] — connection knobs
117//! - [`WireGuardConfig`] / [`WireGuardPeer`] — WireGuard configuration
118//! - [`OpenVpnConfig`] / [`OpenVpnAuthType`] / [`OpenVpnProxy`] — OpenVPN configuration
119//! - [`VpnConfig`] / [`VpnConfiguration`] — generic VPN dispatch trait/enum
120//! - [`VpnConnection`] / [`VpnConnectionInfo`] / [`VpnDetails`] / [`VpnType`] / [`VpnKind`] — saved or active VPN data
121//! - [`SavedConnection`] / [`SavedConnectionBrief`] / [`SettingsSummary`] / [`SettingsPatch`] — saved profile management
122//! - [`AirplaneModeState`] / [`RadioState`] — radio/rfkill state
123//! - [`BluetoothDevice`] / [`BluetoothIdentity`] / [`BluetoothNetworkRole`] — Bluetooth networking
124//! - [`ConnectivityState`] / [`ConnectivityReport`] — internet connectivity
125//! - [`ConnectionError`] / [`StateReason`] / [`ConnectionStateReason`] — errors
126//!
127//! [`VpnCredentials`] is still re-exported but is **deprecated**; new code
128//! should use [`WireGuardConfig`] together with [`NetworkManager::connect_vpn`].
129//!
130//! ## Connection Builders
131//!
132//! The [`builders`] module provides both fluent builder types
133//! ([`builders::ConnectionBuilder`], [`builders::WifiConnectionBuilder`],
134//! [`builders::WireGuardBuilder`], [`builders::OpenVpnBuilder`]) and
135//! free functions (`build_wifi_connection`, `build_ethernet_connection`,
136//! `build_wireguard_connection`, `build_openvpn_connection`,
137//! `build_bluetooth_connection`, `build_vlan_connection`) for constructing
138//! NetworkManager settings dictionaries. Most callers should reach for the
139//! higher-level [`NetworkManager`] API; these builders are exposed for
140//! advanced use cases that need to assemble the raw settings dictionary
141//! before calling a D-Bus method directly.
142//!
143//! ## Secret Agent
144//!
145//! The [`agent`] module lets a consumer register a NetworkManager **secret
146//! agent** to handle interactive credential prompts (Wi-Fi passwords, VPN
147//! tokens, 802.1X passwords) over D-Bus. See the module docs for the
148//! three-stream model and a full example.
149//!
150//! # Examples
151//!
152//! ## Connecting to Different Network Types
153//!
154//! ```rust
155//! use nmrs::{NetworkManager, WifiSecurity, EapOptions, EapMethod, Phase2};
156//!
157//! # async fn example() -> nmrs::Result<()> {
158//! let nm = NetworkManager::new().await?;
159//!
160//! // Open network
161//! nm.connect("OpenWiFi", None, WifiSecurity::Open).await?;
162//!
163//! // WPA-PSK (password-protected)
164//! nm.connect("HomeWiFi", None, WifiSecurity::WpaPsk {
165//! psk: "my_password".into()
166//! }).await?;
167//!
168//! // WPA-EAP (Enterprise)
169//! let eap_opts = EapOptions::new("user@company.com", "password")
170//! .with_domain_suffix_match("company.com")
171//! .with_system_ca_certs(true)
172//! .with_method(EapMethod::Peap)
173//! .with_phase2(Phase2::Mschapv2);
174//!
175//! nm.connect("CorpWiFi", None, WifiSecurity::WpaEap {
176//! opts: eap_opts
177//! }).await?;
178//!
179//! // Ethernet (auto-connects when cable is plugged in)
180//! nm.connect_wired().await?;
181//! # Ok(())
182//! # }
183//! ```
184//!
185//! ## Error Handling
186//!
187//! All operations return [`Result<T>`], which is an alias for `Result<T, ConnectionError>`.
188//! The [`ConnectionError`] type provides specific variants for different failure modes:
189//!
190//! ```rust
191//! use nmrs::{NetworkManager, WifiSecurity, ConnectionError};
192//!
193//! # async fn example() -> nmrs::Result<()> {
194//! let nm = NetworkManager::new().await?;
195//!
196//! match nm.connect("MyNetwork", None, WifiSecurity::WpaPsk {
197//! psk: "wrong_password".into()
198//! }).await {
199//! Ok(_) => println!("Connected successfully"),
200//! Err(ConnectionError::AuthFailed) => {
201//! eprintln!("Wrong password!");
202//! }
203//! Err(ConnectionError::NotFound) => {
204//! eprintln!("Network not found or out of range");
205//! }
206//! Err(ConnectionError::Timeout) => {
207//! eprintln!("Connection timed out");
208//! }
209//! Err(ConnectionError::DhcpFailed) => {
210//! eprintln!("Failed to obtain IP address");
211//! }
212//! Err(e) => eprintln!("Error: {}", e),
213//! }
214//! # Ok(())
215//! # }
216//! ```
217//!
218//! ## Device Management
219//!
220//! ```rust
221//! use nmrs::NetworkManager;
222//!
223//! # async fn example() -> nmrs::Result<()> {
224//! let nm = NetworkManager::new().await?;
225//!
226//! // List all devices
227//! let devices = nm.list_devices().await?;
228//! for device in devices {
229//! println!("{}: {} ({})",
230//! device.interface,
231//! device.device_type,
232//! device.state
233//! );
234//! }
235//!
236//! // Enable/disable WiFi
237//! nm.set_wireless_enabled(false).await?;
238//! nm.set_wireless_enabled(true).await?;
239//! # Ok(())
240//! # }
241//! ```
242//!
243//! ## Real-Time Monitoring
244//!
245//! Monitor network and device changes in real-time using D-Bus signals:
246//!
247//! ```rust
248//! use nmrs::NetworkManager;
249//!
250//! # async fn example() -> nmrs::Result<()> {
251//! let nm = NetworkManager::new().await?;
252//!
253//! // Monitor network changes (new networks, signal changes, etc.)
254//! nm.monitor_network_changes(|| {
255//! println!("Networks changed! Refresh your UI.");
256//! }).await?;
257//!
258//! // Monitor device state changes (cable plugged in, device activated, etc.)
259//! nm.monitor_device_changes(|| {
260//! println!("Device state changed!");
261//! }).await?;
262//! # Ok(())
263//! # }
264//! ```
265//!
266//! # Architecture
267//!
268//! This crate uses D-Bus signals for efficient state monitoring instead of polling.
269//! When connecting to a network, it subscribes to NetworkManager's `StateChanged`
270//! signals to detect connection success or failure immediately. This provides:
271//!
272//! - **Faster response times** - Immediate notification vs polling delay
273//! - **Lower CPU usage** - No spinning loops
274//! - **Better error messages** - Specific failure reasons from NetworkManager
275//!
276//! # Logging
277//!
278//! This crate uses the [`log`](https://docs.rs/log) facade. To see log output,
279//! add a logging implementation like `env_logger`:
280//!
281//! ```no_run,ignore
282//! env_logger::init();
283//! ```
284//!
285//! # Feature Flags
286//!
287//! This crate currently has no optional features. All functionality is enabled by default.
288//!
289//! # Platform Support
290//!
291//! This crate is Linux-only and requires:
292//! - NetworkManager running and accessible via D-Bus
293//! - Appropriate permissions to manage network connections
294
295// Internal modules (not exposed in public API)
296mod api;
297mod core;
298mod dbus;
299mod monitoring;
300mod types;
301mod util;
302
303/// NetworkManager secret agent for credential prompting over D-Bus.
304///
305/// See the [module documentation](agent) for the three-stream model,
306/// lifecycle, and a full example.
307pub mod agent;
308
309// ============================================================================
310// Public API
311// ============================================================================
312
313/// Connection builders for Wi-Fi, Ethernet, Bluetooth, VLAN, and VPN connections.
314///
315/// This module provides two complementary APIs for constructing NetworkManager
316/// settings dictionaries:
317///
318/// - **Fluent builder types** — [`ConnectionBuilder`](builders::ConnectionBuilder),
319/// [`WifiConnectionBuilder`](builders::WifiConnectionBuilder),
320/// [`WireGuardBuilder`](builders::WireGuardBuilder), and
321/// [`OpenVpnBuilder`](builders::OpenVpnBuilder), which support method
322/// chaining and validation at `.build()`.
323/// - **Free functions** — `build_wifi_connection`, `build_ethernet_connection`,
324/// `build_wireguard_connection`, `build_openvpn_connection`,
325/// `build_bluetooth_connection`, and `build_vlan_connection`, which are
326/// handy for one-shot construction.
327///
328/// Most callers should prefer [`NetworkManager`](crate::NetworkManager)'s
329/// high-level methods such as [`connect`](crate::NetworkManager::connect)
330/// and [`connect_vpn`](crate::NetworkManager::connect_vpn). Use these
331/// builders only when you need to feed a raw settings dictionary to
332/// NetworkManager's `AddConnection` or `AddAndActivateConnection` D-Bus
333/// methods directly.
334///
335/// # Example
336///
337/// ```rust
338/// use nmrs::builders::build_wifi_connection;
339/// use nmrs::{ConnectionOptions, WifiSecurity};
340///
341/// let opts = ConnectionOptions::new(true);
342/// let settings = build_wifi_connection("MyNetwork", &WifiSecurity::Open, &opts);
343/// // `settings` can be passed straight to NetworkManager via D-Bus.
344/// ```
345pub mod builders {
346 pub use crate::api::builders::*;
347}
348
349/// Types, enums, and errors for NetworkManager operations.
350///
351/// This module re-exports every public data type used by the crate.
352/// The same types are also re-exported at the crate root for convenience
353/// (so `nmrs::Device` and `nmrs::models::Device` refer to the same type),
354/// with the exceptions of [`NetworkManager`](crate::NetworkManager) and
355/// [`WifiScope`](crate::WifiScope), which live only at the crate root.
356///
357/// # Core Data Types
358/// - [`Device`] — Network device representation
359/// - [`Network`] — Wi-Fi network representation (SSID-grouped)
360/// - [`AccessPoint`] — Per-BSSID access point details
361/// - [`NetworkInfo`] — Detailed network information returned by `show_details`
362/// - [`WifiDevice`] — Wi-Fi-specific device summary
363/// - [`BluetoothDevice`] — Discovered Bluetooth peer
364/// - [`SavedConnection`] / [`SavedConnectionBrief`] — Saved profile snapshots
365/// - [`SettingsSummary`] / [`SettingsPatch`] — Decoded NM settings & update patches
366/// - [`VpnConnection`] / [`VpnConnectionInfo`] / [`VpnDetails`] — Active or saved VPN data
367///
368/// # Configuration
369/// - [`WifiSecurity`] — Wi-Fi security types (Open, WPA-PSK, WPA-EAP)
370/// - [`EapOptions`] — Enterprise authentication options
371/// - [`ConnectionOptions`] — Connection settings (autoconnect, priority, retries)
372/// - [`TimeoutConfig`] — Timeout configuration for connection operations
373/// - [`WireGuardConfig`] / [`WireGuardPeer`] — WireGuard tunnel configuration
374/// - [`OpenVpnConfig`] — OpenVPN plugin configuration
375/// - [`VlanConfig`] — VLAN tagging configuration
376/// - [`BluetoothIdentity`] — Bluetooth target (bdaddr + role)
377/// - [`VpnConfig`] / [`VpnConfiguration`] — Trait & enum used by `connect_vpn`
378///
379/// # Enums
380/// - [`DeviceType`] — Device types (Ethernet, Wi-Fi, Bluetooth, etc.)
381/// - [`DeviceState`] — Device states (Disconnected, Activated, etc.)
382/// - [`ActiveConnectionState`] — State of an active connection
383/// - [`ConnectivityState`] — NM-reported internet connectivity
384/// - [`RadioState`] / [`AirplaneModeState`] — Radio/rfkill state
385/// - [`ApMode`] — Access point operating mode
386/// - [`BluetoothNetworkRole`] — PAN-U / NAP / DUN roles
387/// - [`EapMethod`] — EAP authentication methods
388/// - [`Phase2`] — Phase 2 authentication for EAP
389/// - [`OpenVpnAuthType`] / [`OpenVpnConnectionType`] / [`OpenVpnCompression`] — OpenVPN auth/transport options
390/// - [`OpenVpnProxy`] — OpenVPN HTTP/SOCKS proxy configuration
391/// - [`VpnKind`] / [`VpnType`] — Plugin vs. kernel WireGuard, plus protocol-specific metadata
392/// - [`VpnSecretFlags`] — NM secret flags for VPN credentials
393/// - [`WifiKeyMgmt`] / [`WifiSecuritySummary`] / [`SecurityFeatures`] — Decoded Wi-Fi security info
394/// - [`ConnectType`] — How a `connect_vpn` call resolved (saved vs. new)
395///
396/// # Errors
397/// - [`ConnectionError`] — Comprehensive error type for all operations
398/// - [`StateReason`] — Device state change reasons
399/// - [`ConnectionStateReason`] — Connection state change reasons
400///
401/// # Helper Functions
402/// - [`reason_to_error`] — Convert a device state reason to a [`ConnectionError`]
403/// - [`connection_state_reason_to_error`] — Convert an active-connection state reason to a [`ConnectionError`]
404pub mod models {
405 pub use crate::api::models::*;
406}
407
408// Re-export commonly used types at crate root for convenience
409#[allow(deprecated)]
410pub use api::models::{
411 AccessPoint, ActiveConnectionState, AirplaneModeState, ApMode, BluetoothDevice,
412 BluetoothIdentity, BluetoothNetworkRole, ConnectType, ConnectionError, ConnectionOptions,
413 ConnectionStateReason, ConnectivityReport, ConnectivityState, Device, DeviceState, DeviceType,
414 EapMethod, EapOptions, Network, NetworkInfo, OpenVpnAuthType, OpenVpnCompression,
415 OpenVpnConfig, OpenVpnConnectionType, OpenVpnProxy, Phase2, RadioState, SavedConnection,
416 SavedConnectionBrief, SecurityFeatures, SettingsPatch, SettingsSummary, StateReason,
417 TimeoutConfig, VlanConfig, VpnConfig, VpnConfiguration, VpnConnection, VpnConnectionInfo,
418 VpnCredentials, VpnDetails, VpnKind, VpnRoute, VpnSecretFlags, VpnType, WifiDevice,
419 WifiKeyMgmt, WifiSecurity, WifiSecuritySummary, WireGuardConfig, WireGuardPeer,
420 connection_state_reason_to_error, reason_to_error,
421};
422pub use api::network_manager::NetworkManager;
423pub use api::wifi_scope::WifiScope;
424
425/// A specialized `Result` type for network operations.
426///
427/// This is an alias for `Result<T, ConnectionError>` and is used throughout
428/// the crate for all fallible operations.
429///
430/// # Examples
431///
432/// ```rust
433/// use nmrs::Result;
434///
435/// async fn connect_to_wifi() -> Result<()> {
436/// // Your code here
437/// Ok(())
438/// }
439/// ```
440pub type Result<T> = std::result::Result<T, ConnectionError>;