Work on UAPI parser
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use spin::Mutex;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::time::SystemTime;
|
||||
use x25519_dalek::{PublicKey, StaticSecret};
|
||||
|
||||
use super::*;
|
||||
@@ -11,12 +13,12 @@ use bind::Owner;
|
||||
|
||||
/// Describes a snapshot of the state of a peer
|
||||
pub struct PeerState {
|
||||
rx_bytes: u64,
|
||||
tx_bytes: u64,
|
||||
last_handshake_time_sec: u64,
|
||||
last_handshake_time_nsec: u64,
|
||||
public_key: PublicKey,
|
||||
allowed_ips: Vec<(IpAddr, u32)>,
|
||||
pub rx_bytes: u64,
|
||||
pub tx_bytes: u64,
|
||||
pub last_handshake_time_sec: u64,
|
||||
pub last_handshake_time_nsec: u64,
|
||||
pub public_key: PublicKey,
|
||||
pub allowed_ips: Vec<(IpAddr, u32)>,
|
||||
}
|
||||
|
||||
pub struct WireguardConfig<T: tun::Tun, B: bind::Platform> {
|
||||
@@ -33,23 +35,6 @@ impl<T: tun::Tun, B: bind::Platform> WireguardConfig<T, B> {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ConfigError {
|
||||
NoSuchPeer,
|
||||
NotListening,
|
||||
FailedToBind,
|
||||
}
|
||||
|
||||
impl ConfigError {
|
||||
fn errno(&self) -> i32 {
|
||||
// TODO: obtain the correct error values
|
||||
match self {
|
||||
ConfigError::NoSuchPeer => 1,
|
||||
ConfigError::NotListening => 2,
|
||||
ConfigError::FailedToBind => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Exposed configuration interface
|
||||
pub trait Configuration {
|
||||
/// Updates the private key of the device
|
||||
@@ -244,7 +229,7 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> {
|
||||
}
|
||||
|
||||
fn add_peer(&self, peer: &PublicKey) -> bool {
|
||||
self.wireguard.new_peer(*peer);
|
||||
self.wireguard.add_peer(*peer);
|
||||
false
|
||||
}
|
||||
|
||||
@@ -301,6 +286,24 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> {
|
||||
}
|
||||
|
||||
fn get_peers(&self) -> Vec<PeerState> {
|
||||
vec![]
|
||||
let peers = self.wireguard.list_peers();
|
||||
let mut state = Vec::with_capacity(peers.len());
|
||||
for p in peers {
|
||||
// convert the system time to (secs, nano) since epoch
|
||||
let last_handshake = (*p.walltime_last_handshake.lock())
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.expect("There should be no earlier time");
|
||||
|
||||
// extract state into PeerState
|
||||
state.push(PeerState {
|
||||
rx_bytes: p.rx_bytes.load(Ordering::Relaxed),
|
||||
tx_bytes: p.tx_bytes.load(Ordering::Relaxed),
|
||||
allowed_ips: p.router.list_allowed_ips(),
|
||||
last_handshake_time_nsec: last_handshake.subsec_nanos() as u64,
|
||||
last_handshake_time_sec: last_handshake.as_secs(),
|
||||
public_key: p.pk,
|
||||
})
|
||||
}
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
28
src/configuration/error.rs
Normal file
28
src/configuration/error.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
pub enum ConfigError {
|
||||
NoSuchPeer,
|
||||
NotListening,
|
||||
FailedToBind,
|
||||
InvalidHexValue,
|
||||
InvalidPortNumber,
|
||||
InvalidFwmark,
|
||||
InvalidKey,
|
||||
UnsupportedValue,
|
||||
UnsupportedProtocolVersion,
|
||||
}
|
||||
|
||||
impl ConfigError {
|
||||
fn errno(&self) -> i32 {
|
||||
// TODO: obtain the correct error values
|
||||
match self {
|
||||
ConfigError::NoSuchPeer => 1,
|
||||
ConfigError::NotListening => 2,
|
||||
ConfigError::FailedToBind => 3,
|
||||
ConfigError::InvalidHexValue => 4,
|
||||
ConfigError::InvalidPortNumber => 5,
|
||||
ConfigError::InvalidFwmark => 6,
|
||||
ConfigError::UnsupportedValue => 7,
|
||||
ConfigError::InvalidKey => 8,
|
||||
ConfigError::UnsupportedProtocolVersion => 9,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
mod config;
|
||||
mod error;
|
||||
mod uapi;
|
||||
|
||||
use super::platform::Endpoint;
|
||||
use super::platform::{bind, tun};
|
||||
use super::wireguard::Wireguard;
|
||||
|
||||
pub use error::ConfigError;
|
||||
|
||||
pub use config::Configuration;
|
||||
pub use config::WireguardConfig;
|
||||
|
||||
161
src/configuration/uapi.rs
Normal file
161
src/configuration/uapi.rs
Normal file
@@ -0,0 +1,161 @@
|
||||
use hex::FromHex;
|
||||
use x25519_dalek::{PublicKey, StaticSecret};
|
||||
|
||||
use super::{ConfigError, Configuration};
|
||||
|
||||
struct StreamPeer {
|
||||
public_key: PublicKey,
|
||||
update_only: bool,
|
||||
added: bool,
|
||||
}
|
||||
|
||||
struct StreamParser<C: Configuration> {
|
||||
config: C,
|
||||
update_only: bool,
|
||||
peer: Option<StreamPeer>,
|
||||
}
|
||||
|
||||
impl<C: Configuration> StreamParser<C> {
|
||||
fn parse_interface_line(&mut self, key: &str, value: &str) -> (bool, Option<ConfigError>) {
|
||||
let err = match key {
|
||||
"private_key" => match <[u8; 32]>::from_hex(value) {
|
||||
Ok(sk) => {
|
||||
self.config.set_private_key(if sk == [0u8; 32] {
|
||||
None
|
||||
} else {
|
||||
Some(StaticSecret::from(sk))
|
||||
});
|
||||
None
|
||||
}
|
||||
Err(_) => Some(ConfigError::InvalidHexValue),
|
||||
},
|
||||
"listen_port" => match value.parse() {
|
||||
Ok(port) => {
|
||||
self.config.set_listen_port(Some(port));
|
||||
None
|
||||
}
|
||||
Err(_) => Some(ConfigError::InvalidPortNumber),
|
||||
},
|
||||
"fwmark" => match value.parse() {
|
||||
Ok(fwmark) => {
|
||||
self.config
|
||||
.set_fwmark(if fwmark == 0 { None } else { Some(fwmark) });
|
||||
None
|
||||
}
|
||||
Err(_) => Some(ConfigError::InvalidFwmark),
|
||||
},
|
||||
"replace_peers" => match value {
|
||||
"true" => {
|
||||
for p in self.config.get_peers() {
|
||||
self.config.remove_peer(&p.public_key)
|
||||
}
|
||||
None
|
||||
}
|
||||
_ => Some(ConfigError::UnsupportedValue),
|
||||
},
|
||||
|
||||
// transition to peer configuration
|
||||
"public_key" => {
|
||||
return (true, None);
|
||||
}
|
||||
|
||||
// unknown key
|
||||
_ => Some(ConfigError::InvalidKey),
|
||||
};
|
||||
(false, err)
|
||||
}
|
||||
|
||||
fn parse_peer_line(&mut self, key: &str, value: &str) -> Option<ConfigError> {
|
||||
// add a p
|
||||
let mut flush_peer = || match self.peer.as_mut() {
|
||||
None => (),
|
||||
Some(peer) => {
|
||||
if !peer.added {
|
||||
peer.added = true;
|
||||
if !peer.update_only {
|
||||
self.config.add_peer(&peer.public_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match key {
|
||||
// new peer
|
||||
"public_key" => {
|
||||
// add previous peer
|
||||
flush_peer();
|
||||
|
||||
// create state for new peer
|
||||
match <[u8; 32]>::from_hex(value) {
|
||||
Ok(pk) => {
|
||||
self.peer = Some(StreamPeer {
|
||||
public_key: PublicKey::from(pk),
|
||||
update_only: false,
|
||||
added: false,
|
||||
});
|
||||
None
|
||||
}
|
||||
Err(_) => Some(ConfigError::InvalidHexValue),
|
||||
}
|
||||
}
|
||||
|
||||
"remove" => {
|
||||
let peer = self.peer.as_ref().unwrap();
|
||||
self.config.remove_peer(&peer.public_key);
|
||||
None
|
||||
}
|
||||
|
||||
"update_only" => {
|
||||
let peer = self.peer.as_mut().unwrap();
|
||||
peer.update_only = true;
|
||||
None
|
||||
}
|
||||
|
||||
"preshared_key" => {
|
||||
// add peer (if not exists)
|
||||
let peer = self.peer.as_mut().unwrap();
|
||||
if !peer.added && !peer.update_only {
|
||||
self.config.add_peer(&peer.public_key);
|
||||
peer.added = true;
|
||||
}
|
||||
|
||||
// set preshared key
|
||||
match <[u8; 32]>::from_hex(value) {
|
||||
Ok(psk) => {
|
||||
self.config.set_preshared_key(
|
||||
&peer.public_key,
|
||||
if psk == [0u8; 32] { None } else { Some(psk) },
|
||||
);
|
||||
None
|
||||
}
|
||||
Err(_) => Some(ConfigError::InvalidHexValue),
|
||||
}
|
||||
}
|
||||
|
||||
"endpoint" => None,
|
||||
|
||||
"persistent_keepalive_interval" => None,
|
||||
|
||||
"replace_allowed_ips" => None,
|
||||
|
||||
"allowed_ip" => None,
|
||||
|
||||
// set protocol version of peer
|
||||
"protocol_version" => {
|
||||
let parse_res: Result<usize, _> = value.parse();
|
||||
match parse_res {
|
||||
Ok(version) => {
|
||||
if version == 0 || version > self.config.get_protocol_version() {
|
||||
Some(ConfigError::UnsupportedProtocolVersion)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Err(_) => Some(ConfigError::UnsupportedProtocolVersion),
|
||||
}
|
||||
}
|
||||
// unknown key
|
||||
_ => Some(ConfigError::InvalidKey),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,8 +120,8 @@ fn test_pure_wireguard() {
|
||||
|
||||
let pk2 = PublicKey::from(&sk2);
|
||||
|
||||
wg1.new_peer(pk2);
|
||||
wg2.new_peer(pk1);
|
||||
wg1.add_peer(pk2);
|
||||
wg2.add_peer(pk1);
|
||||
|
||||
wg1.set_key(Some(sk1));
|
||||
wg2.set_key(Some(sk2));
|
||||
|
||||
@@ -148,16 +148,6 @@ impl<B: Bind> PeerInner<B> {
|
||||
self.queue.lock().send(HandshakeJob::New(self.pk)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_persistent_keepalive_interval(&self, interval: usize) {
|
||||
self.timers().send_persistent_keepalive.stop();
|
||||
self.keepalive.store(interval, Ordering::SeqCst);
|
||||
if interval > 0 {
|
||||
self.timers()
|
||||
.send_persistent_keepalive
|
||||
.start(Duration::from_secs(internal as u64));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Handshake {
|
||||
@@ -260,7 +250,11 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
|
||||
self.state.handshake.write().device.set_psk(pk, psk).is_ok()
|
||||
}
|
||||
|
||||
pub fn new_peer(&self, pk: PublicKey) {
|
||||
pub fn add_peer(&self, pk: PublicKey) {
|
||||
if self.state.peers.read().contains_key(pk.as_bytes()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
let state = Arc::new(PeerInner {
|
||||
id: rng.gen(),
|
||||
@@ -278,9 +272,6 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
|
||||
// create a router peer
|
||||
let router = Arc::new(self.state.router.new_peer(state.clone()));
|
||||
|
||||
// add to the handshake device
|
||||
self.state.handshake.write().device.add(pk).unwrap(); // TODO: handle adding of public key for interface
|
||||
|
||||
// form WireGuard peer
|
||||
let peer = Peer { router, state };
|
||||
|
||||
@@ -295,6 +286,9 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
|
||||
// finally, add the peer to the wireguard device
|
||||
let mut peers = self.state.peers.write();
|
||||
peers.entry(*pk.as_bytes()).or_insert(peer);
|
||||
|
||||
// add to the handshake device
|
||||
self.state.handshake.write().device.add(pk).unwrap(); // TODO: handle adding of public key for interface
|
||||
}
|
||||
|
||||
/* Begin consuming messages from the reader.
|
||||
|
||||
Reference in New Issue
Block a user