WireGuard VPN Client
This example demonstrates a complete WireGuard VPN client that connects, displays connection information, and cleanly disconnects.
Features
- Builds VPN credentials with the builder pattern
- Connects and retrieves VPN details
- Displays IP configuration and DNS
- Cleanly disconnects on completion
Code
use nmrs::{NetworkManager, VpnCredentials, WireGuardPeer}; #[tokio::main] async fn main() -> nmrs::Result<()> { let nm = NetworkManager::new().await?; // Check for existing VPN connections let existing = nm.list_vpn_connections().await?; if !existing.is_empty() { println!("Existing VPN connections:"); for vpn in &existing { println!(" {} ({:?}) — {:?}", vpn.name, vpn.vpn_type, vpn.state); } println!(); } // Build WireGuard peer configuration let peer = WireGuardPeer::new( std::env::var("WG_SERVER_PUBKEY") .expect("Set WG_SERVER_PUBKEY"), std::env::var("WG_ENDPOINT") .unwrap_or_else(|_| "vpn.example.com:51820".into()), vec!["0.0.0.0/0".into()], ) .with_persistent_keepalive(25); // Build credentials let creds = VpnCredentials::builder() .name("ExampleVPN") .wireguard() .gateway( std::env::var("WG_ENDPOINT") .unwrap_or_else(|_| "vpn.example.com:51820".into()), ) .private_key( std::env::var("WG_PRIVATE_KEY") .expect("Set WG_PRIVATE_KEY"), ) .address( std::env::var("WG_ADDRESS") .unwrap_or_else(|_| "10.0.0.2/24".into()), ) .add_peer(peer) .with_dns(vec!["1.1.1.1".into(), "8.8.8.8".into()]) .with_mtu(1420) .build(); // Connect println!("Connecting to VPN..."); nm.connect_vpn(creds).await?; println!("Connected!\n"); // Show VPN details let info = nm.get_vpn_info("ExampleVPN").await?; println!("VPN Connection Details:"); println!(" Name: {}", info.name); println!(" Type: {:?}", info.vpn_type); println!(" State: {:?}", info.state); println!(" Interface: {:?}", info.interface); println!(" Gateway: {:?}", info.gateway); println!(" IPv4: {:?}", info.ip4_address); println!(" IPv6: {:?}", info.ip6_address); println!(" DNS: {:?}", info.dns_servers); // Wait for user input before disconnecting println!("\nPress Enter to disconnect..."); let mut input = String::new(); std::io::stdin().read_line(&mut input).ok(); // Disconnect nm.disconnect_vpn("ExampleVPN").await?; println!("VPN disconnected"); // Optionally remove the profile // nm.forget_vpn("ExampleVPN").await?; Ok(()) }
Running
WG_SERVER_PUBKEY="HIgo9xNzJMWLKAShlKl6/bUT1VI9Q0SDBXGtLXkPFXc=" \
WG_PRIVATE_KEY="YBk6X3pP8KjKz7+HFWzVHNqL3qTZq8hX9VxFQJ4zVmM=" \
WG_ENDPOINT="vpn.example.com:51820" \
WG_ADDRESS="10.0.0.2/24" \
cargo run --example wireguard_client
Sample Output
Connecting to VPN...
Connected!
VPN Connection Details:
Name: ExampleVPN
Type: WireGuard
State: Activated
Interface: Some("wg-examplevpn")
Gateway: Some("vpn.example.com")
IPv4: Some("10.0.0.2/24")
IPv6: None
DNS: ["1.1.1.1", "8.8.8.8"]
Press Enter to disconnect...
Split Tunnel Variation
Route only specific subnets through the VPN:
#![allow(unused)] fn main() { let peer = WireGuardPeer::new( "server_public_key", "vpn.example.com:51820", vec![ "10.0.0.0/8".into(), "192.168.0.0/16".into(), ], ); }
Multiple Peers
Connect through multiple WireGuard servers:
#![allow(unused)] fn main() { let peer1 = WireGuardPeer::new( "peer1_pubkey", "us-east.vpn.example.com:51820", vec!["10.1.0.0/16".into()], ); let peer2 = WireGuardPeer::new( "peer2_pubkey", "eu-west.vpn.example.com:51820", vec!["10.2.0.0/16".into()], ); let creds = VpnCredentials::builder() .name("MultiPeerVPN") .wireguard() .gateway("us-east.vpn.example.com:51820") .private_key("client_private_key") .address("10.0.0.2/24") .add_peer(peer1) .add_peer(peer2) .build(); }