Files
nym/gateway/src/node/wireguard.rs
T
2023-07-25 16:46:24 +02:00

113 lines
4.6 KiB
Rust

use std::sync::Arc;
use base64::engine::general_purpose;
use base64::Engine as _;
use boringtun::noise::{rate_limiter::RateLimiter, Tunn, TunnResult};
use log::{debug, error, info};
use tokio::{net::UdpSocket, sync::Mutex};
use x25519_dalek::{PublicKey, StaticSecret};
pub async fn wireguard() {
let wg_address = "127.0.0.1:51820";
let sock = UdpSocket::bind(wg_address).await.unwrap();
info!("wg listening on {wg_address}");
// Secret key ofthe gateway, we'll need a way to generate this from the IdentityKey, might be enough to do some base58 -> base64 conversion
let secret_bytes: [u8; 32] = general_purpose::STANDARD
.decode("MBbPChSpmC/FXwIWNROltjd6cOywC81GNEgH9jMOOFk=")
.unwrap()
.try_into()
.unwrap();
// Hardcoded peer public key, we'll need a way to register those, private key for that one is `aMUcuAgTiFCHQ/fHqEQRvpLWBxh8sKA7f7lSyWymrGE=`
// Wireguard configuration that works with this setup is below, this needs to be put into the wireguard client of choice.
// Working in this case means that they go through the handshake, and client
// starts sending data packets to the gateway.
//
// [Interface]
// PrivateKey = aMUcuAgTiFCHQ/fHqEQRvpLWBxh8sKA7f7lSyWymrGE=
// Address = 10.8.0.0/24
// DNS = 1.1.1.1
//
// [Peer]
// PublicKey = y6/iGYraJjON6pw9fcBa5vLRbGsQqprFLfWKyJQnlWs=
// AllowedIPs = 0.0.0.0/0
// Endpoint = 127.0.0.1:51820
let peer_public_bytes: [u8; 32] = general_purpose::STANDARD
.decode("JpJzoO1DY6HZbn2h33GQJg0GLnxfdpOeV9C/rvdZ5Cs=")
.unwrap()
.try_into()
.unwrap();
let peer_public = PublicKey::from(peer_public_bytes);
let secret = StaticSecret::try_from(secret_bytes).unwrap();
let public = PublicKey::from(&secret);
info!(
"wg public key: {}",
general_purpose::STANDARD.encode(public)
);
// Rate limiter is global for the gateway
let rate_limiter = Arc::new(RateLimiter::new(&public, 1024));
let tun = Arc::new(Mutex::new(
Tunn::new(secret, peer_public, None, None, 0, Some(rate_limiter)).unwrap(),
));
// Here we have a pretty suboptimal implementation of the UDP communication, for one client
loop {
let mut buf = [0; 1024];
let mut dst = vec![0; 1024];
let (len, addr) = sock.recv_from(&mut buf).await.unwrap();
let packet = Tunn::parse_incoming_packet(&buf[..len]).unwrap();
info!("packet: {:?}", packet);
let dst_addr = Tunn::dst_address(&buf[..len]);
debug!("dst_addr: {:?}", dst_addr);
let result = {
let mut t = tun.lock().await;
t.decapsulate(dst_addr, &buf[..len], &mut dst)
};
loop {
let tun = Arc::clone(&tun);
debug!("result: {:?}", result);
match result {
TunnResult::Done => break,
// We'll get here during the handshake process, if the reponse is WriteToNetwork we should call decapsulate again with an
// empty datagram until we get a Done response
TunnResult::WriteToNetwork(p) => {
let len = sock.send_to(p, addr).await.unwrap();
debug!("{} bytes sent to {}", len, addr);
let mut t = tun.lock().await;
t.decapsulate(dst_addr, &[], p);
break;
}
TunnResult::Err(e) => {
error!("error: {:?}", e);
break;
}
// We've recieved some DataPackets we need to forward and send response back to the initiating client
// if no data packets are available we should send an empty packet as an ack.
// For now this just logs that it received the packet, and send and ack back to the client.
TunnResult::WriteToTunnelV4(ref _r, _addy) => {
// These are very spammy
debug!("WriteToTunnelV4");
let mut t = tun.lock().await;
sock.send_to(&empty_packet(&mut t), addr).await.unwrap();
break;
}
TunnResult::WriteToTunnelV6(ref _r, _addy) => {
// These are very spammy
debug!("WriteToTunnelV6");
let mut t = tun.lock().await;
sock.send_to(&empty_packet(&mut t), addr).await.unwrap();
break;
}
}
}
}
}
fn empty_packet(tun: &mut Tunn) -> [u8; 128] {
let mut dst = [0; 128];
tun.encapsulate(&[], &mut dst);
dst
}