use std::io::{Read, Write};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use ipnet::{Ipv4Net, Ipv6Net};
use log::*;
fn main() {
env_logger::init();
let private = x25519_dalek::StaticSecret::random();
let public = x25519_dalek::PublicKey::from(&private);
let (demo_pub, internal_ip, endpoint) =
get_demo_server_config(public.as_bytes()).expect("Failed to get demo server credentials");
println!("Connecting to {} - internal ip: {}", endpoint, internal_ip);
let wireguard =
unsafe { wireguard_nt::load_from_path("examples/wireguard_nt/bin/amd64/wireguard.dll") }
.expect("Failed to load wireguard dll");
let adapter = wireguard_nt::Adapter::open(&wireguard, "Demo").unwrap_or_else(|_| {
wireguard_nt::Adapter::create(&wireguard, "WireGuard", "Demo", None)
.expect("Failed to create wireguard adapter!")
});
let mut interface_private = [0; 32];
let mut peer_pub = [0; 32];
interface_private.copy_from_slice(private.as_bytes());
peer_pub.copy_from_slice(demo_pub.as_slice());
let allowed_ip = match endpoint.ip() {
IpAddr::V4(v4) => Ipv4Net::new(v4, 32).unwrap().into(),
IpAddr::V6(v6) => Ipv6Net::new(v6, 128).unwrap().into(),
};
let interface = wireguard_nt::SetInterface {
listen_port: None,
public_key: None,
private_key: Some(interface_private),
peers: vec![wireguard_nt::SetPeer {
public_key: Some(peer_pub),
preshared_key: None,
keep_alive: Some(21),
allowed_ips: vec![allowed_ip], endpoint,
}],
};
assert!(adapter.set_logging(wireguard_nt::AdapterLoggingLevel::OnWithPrefix));
adapter.set_config(&interface).unwrap();
match adapter.set_default_route(&[Ipv4Net::new(internal_ip, 24).unwrap().into()], &interface) {
Ok(()) => {}
Err(err) => panic!("Failed to set default route: {}", err),
}
assert!(adapter.up().is_ok());
println!("Printing peer bandwidth statistics");
println!("Press enter to exit");
let done = Arc::new(AtomicBool::new(false));
let done2 = Arc::clone(&done);
let thread = std::thread::spawn(move || 'outer: loop {
let stats = adapter.get_config();
for peer in stats.peers {
let handshake_age = peer
.last_handshake
.map(|h| SystemTime::now().duration_since(h).unwrap_or_default());
let handshake_msg = match handshake_age {
Some(age) => format!("handshake performed {:.2}s ago", age.as_secs_f32()),
None => "no active handshake".to_string(),
};
println!(
" {:?}, {} bytes up, {} bytes down, {handshake_msg}",
peer.allowed_ips, peer.tx_bytes, peer.rx_bytes
);
}
for _ in 0..10 {
if done2.load(Ordering::Relaxed) {
break 'outer;
}
std::thread::sleep(Duration::from_millis(100));
}
});
let mut _buf = [0u8; 32];
let _ = std::io::stdin().read(&mut _buf);
done.store(true, Ordering::Relaxed);
thread.join().unwrap();
println!("Exiting!");
}
fn get_demo_server_config(pub_key: &[u8]) -> Result<(Vec<u8>, Ipv4Addr, SocketAddr), String> {
use std::net::{TcpStream, ToSocketAddrs};
let addrs: Vec<SocketAddr> = "demo.wireguard.com:42912"
.to_socket_addrs()
.unwrap()
.collect();
let mut s: TcpStream = TcpStream::connect_timeout(
addrs.first().expect("Failed to resolve demo server DNS"),
Duration::from_secs(5),
)
.expect("Failed to open connection to demo server");
let mut encoded = base64::encode(pub_key);
encoded.push('\n');
s.write_all(encoded.as_bytes())
.expect("Failed to write public key to server");
let mut bytes = [0u8; 512];
let len = s.read(&mut bytes).expect("Failed to read from demo server");
let reply = &std::str::from_utf8(&bytes).unwrap()[..len].trim();
info!("Demo server gave: {}", reply);
if !reply.starts_with("OK") {
return Err(format!("Demo Server returned error {}", reply));
}
let parts: Vec<&str> = reply.split(':').collect();
if parts.len() != 4 {
return Err(format!(
"Demo Server returned wrong number of parts. Expected 4 got: {:?}",
parts
));
}
let peer_pub = base64::decode(parts[1])
.map_err(|e| format!("Demo server gave invalid public key: {}", e))?;
let endpoint_port: u16 = parts[2]
.parse()
.map_err(|e| format!("Demo server gave invalid port number: {}", e))?;
let internal_ip = parts[3];
let internal_ip: Ipv4Addr = internal_ip.parse().unwrap();
Ok((
peer_pub,
internal_ip,
SocketAddr::new(addrs[0].ip(), endpoint_port),
))
}