Work on UAPI parser
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, SocketAddr};
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
use std::time::SystemTime;
|
||||||
use x25519_dalek::{PublicKey, StaticSecret};
|
use x25519_dalek::{PublicKey, StaticSecret};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -11,12 +13,12 @@ use bind::Owner;
|
|||||||
|
|
||||||
/// Describes a snapshot of the state of a peer
|
/// Describes a snapshot of the state of a peer
|
||||||
pub struct PeerState {
|
pub struct PeerState {
|
||||||
rx_bytes: u64,
|
pub rx_bytes: u64,
|
||||||
tx_bytes: u64,
|
pub tx_bytes: u64,
|
||||||
last_handshake_time_sec: u64,
|
pub last_handshake_time_sec: u64,
|
||||||
last_handshake_time_nsec: u64,
|
pub last_handshake_time_nsec: u64,
|
||||||
public_key: PublicKey,
|
pub public_key: PublicKey,
|
||||||
allowed_ips: Vec<(IpAddr, u32)>,
|
pub allowed_ips: Vec<(IpAddr, u32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WireguardConfig<T: tun::Tun, B: bind::Platform> {
|
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
|
/// Exposed configuration interface
|
||||||
pub trait Configuration {
|
pub trait Configuration {
|
||||||
/// Updates the private key of the device
|
/// 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 {
|
fn add_peer(&self, peer: &PublicKey) -> bool {
|
||||||
self.wireguard.new_peer(*peer);
|
self.wireguard.add_peer(*peer);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,6 +286,24 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_peers(&self) -> Vec<PeerState> {
|
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 config;
|
||||||
|
mod error;
|
||||||
|
mod uapi;
|
||||||
|
|
||||||
use super::platform::Endpoint;
|
use super::platform::Endpoint;
|
||||||
use super::platform::{bind, tun};
|
use super::platform::{bind, tun};
|
||||||
use super::wireguard::Wireguard;
|
use super::wireguard::Wireguard;
|
||||||
|
|
||||||
|
pub use error::ConfigError;
|
||||||
|
|
||||||
pub use config::Configuration;
|
pub use config::Configuration;
|
||||||
pub use config::WireguardConfig;
|
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);
|
let pk2 = PublicKey::from(&sk2);
|
||||||
|
|
||||||
wg1.new_peer(pk2);
|
wg1.add_peer(pk2);
|
||||||
wg2.new_peer(pk1);
|
wg2.add_peer(pk1);
|
||||||
|
|
||||||
wg1.set_key(Some(sk1));
|
wg1.set_key(Some(sk1));
|
||||||
wg2.set_key(Some(sk2));
|
wg2.set_key(Some(sk2));
|
||||||
|
|||||||
@@ -148,16 +148,6 @@ impl<B: Bind> PeerInner<B> {
|
|||||||
self.queue.lock().send(HandshakeJob::New(self.pk)).unwrap();
|
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 {
|
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()
|
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 mut rng = OsRng::new().unwrap();
|
||||||
let state = Arc::new(PeerInner {
|
let state = Arc::new(PeerInner {
|
||||||
id: rng.gen(),
|
id: rng.gen(),
|
||||||
@@ -278,9 +272,6 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
|
|||||||
// create a router peer
|
// create a router peer
|
||||||
let router = Arc::new(self.state.router.new_peer(state.clone()));
|
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
|
// form WireGuard peer
|
||||||
let peer = Peer { router, state };
|
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
|
// finally, add the peer to the wireguard device
|
||||||
let mut peers = self.state.peers.write();
|
let mut peers = self.state.peers.write();
|
||||||
peers.entry(*pk.as_bytes()).or_insert(peer);
|
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.
|
/* Begin consuming messages from the reader.
|
||||||
|
|||||||
Reference in New Issue
Block a user