more refactoring
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
ace56f32e7
commit
28cbe2ae20
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
pub mod dirsync;
|
pub mod dirsync;
|
||||||
|
|
||||||
use ::num_traits::FromPrimitive;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
connection::{self, ProtocolVersion},
|
connection::{self, ProtocolVersion},
|
||||||
enc::sym::{HeadLen, TagLen},
|
enc::sym::{HeadLen, TagLen},
|
||||||
};
|
};
|
||||||
|
use ::num_traits::FromPrimitive;
|
||||||
|
use ::std::sync::Arc;
|
||||||
|
|
||||||
/// Handshake errors
|
/// Handshake errors
|
||||||
#[derive(::thiserror::Error, Debug, Copy, Clone)]
|
#[derive(::thiserror::Error, Debug, Copy, Clone)]
|
||||||
|
@ -36,8 +36,7 @@ pub(crate) struct HandshakeServer {
|
||||||
pub(crate) struct HandshakeClient {
|
pub(crate) struct HandshakeClient {
|
||||||
pub id: crate::enc::asym::KeyID,
|
pub id: crate::enc::asym::KeyID,
|
||||||
pub key: crate::enc::asym::PrivKey,
|
pub key: crate::enc::asym::PrivKey,
|
||||||
pub hkdf: crate::enc::hkdf::HkdfSha3,
|
pub connection: Arc<crate::connection::Connection>,
|
||||||
pub cipher: crate::enc::sym::CipherKind,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parsed handshake
|
/// Parsed handshake
|
||||||
|
|
|
@ -16,6 +16,13 @@ use crate::enc::{
|
||||||
sym::{CipherKind, CipherRecv, CipherSend},
|
sym::{CipherKind, CipherRecv, CipherSend},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// strong typedef for receiving connection id
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct IDRecv(pub ID);
|
||||||
|
/// strong typedef for sending connection id
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct IDSend(pub ID);
|
||||||
|
|
||||||
/// Version of the fenrir protocol in use
|
/// Version of the fenrir protocol in use
|
||||||
#[derive(::num_derive::FromPrimitive, Debug, Copy, Clone)]
|
#[derive(::num_derive::FromPrimitive, Debug, Copy, Clone)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
@ -37,8 +44,10 @@ impl ProtocolVersion {
|
||||||
/// A single connection and its data
|
/// A single connection and its data
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Connection {
|
pub struct Connection {
|
||||||
/// Connection ID
|
/// Receiving Connection ID
|
||||||
pub id: ID,
|
pub id_recv: IDRecv,
|
||||||
|
/// Sending Connection ID
|
||||||
|
pub id_send: IDSend,
|
||||||
/// The main hkdf used for all secrets in this connection
|
/// The main hkdf used for all secrets in this connection
|
||||||
pub hkdf: HkdfSha3,
|
pub hkdf: HkdfSha3,
|
||||||
/// Cipher for decrypting data
|
/// Cipher for decrypting data
|
||||||
|
@ -78,7 +87,8 @@ impl Connection {
|
||||||
let mut cipher_send = CipherSend::new(cipher, secret_send, rand);
|
let mut cipher_send = CipherSend::new(cipher, secret_send, rand);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
id: ID::Handshake,
|
id_recv: IDRecv(ID::Handshake),
|
||||||
|
id_send: IDSend(ID::Handshake),
|
||||||
hkdf,
|
hkdf,
|
||||||
cipher_recv,
|
cipher_recv,
|
||||||
cipher_send,
|
cipher_send,
|
||||||
|
@ -132,8 +142,8 @@ impl ConnList {
|
||||||
id = (self.ids_used.len() as u64) * 1024;
|
id = (self.ids_used.len() as u64) * 1024;
|
||||||
self.ids_used.push(new_bitmap);
|
self.ids_used.push(new_bitmap);
|
||||||
}
|
}
|
||||||
let new_id = ID::new_u64(id);
|
let new_id = IDRecv(ID::new_u64(id));
|
||||||
conn.id = new_id;
|
conn.id_recv = new_id;
|
||||||
let conn = Arc::new(conn);
|
let conn = Arc::new(conn);
|
||||||
if (self.connections.len() as u64) < id {
|
if (self.connections.len() as u64) < id {
|
||||||
self.connections.push(Some(conn.clone()));
|
self.connections.push(Some(conn.clone()));
|
||||||
|
|
|
@ -106,3 +106,45 @@ pub(crate) struct UdpClient(pub SocketAddr);
|
||||||
/// Strong typedef for a server socket address
|
/// Strong typedef for a server socket address
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub(crate) struct UdpServer(pub SocketAddr);
|
pub(crate) struct UdpServer(pub SocketAddr);
|
||||||
|
|
||||||
|
/// Enable some common socket options. This is just the unsafe part
|
||||||
|
fn enable_sock_opt(
|
||||||
|
fd: ::std::os::fd::RawFd,
|
||||||
|
option: ::libc::c_int,
|
||||||
|
value: ::libc::c_int,
|
||||||
|
) -> ::std::io::Result<()> {
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
unsafe {
|
||||||
|
#[allow(trivial_casts)]
|
||||||
|
let val = &value as *const _ as *const ::libc::c_void;
|
||||||
|
let size = ::std::mem::size_of_val(&value) as ::libc::socklen_t;
|
||||||
|
// always clear the error bit before doing a new syscall
|
||||||
|
let _ = ::std::io::Error::last_os_error();
|
||||||
|
let ret = ::libc::setsockopt(fd, ::libc::SOL_SOCKET, option, val, size);
|
||||||
|
if ret != 0 {
|
||||||
|
return Err(::std::io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/// Add an async udp listener
|
||||||
|
pub async fn bind_udp(sock: SocketAddr) -> ::std::io::Result<UdpSocket> {
|
||||||
|
let socket = UdpSocket::bind(sock).await?;
|
||||||
|
|
||||||
|
use ::std::os::fd::AsRawFd;
|
||||||
|
let fd = socket.as_raw_fd();
|
||||||
|
// can be useful later on for reloads
|
||||||
|
enable_sock_opt(fd, ::libc::SO_REUSEADDR, 1)?;
|
||||||
|
enable_sock_opt(fd, ::libc::SO_REUSEPORT, 1)?;
|
||||||
|
|
||||||
|
// We will do path MTU discovery by ourselves,
|
||||||
|
// always set the "don't fragment" bit
|
||||||
|
if sock.is_ipv6() {
|
||||||
|
enable_sock_opt(fd, ::libc::IPV6_DONTFRAG, 1)?;
|
||||||
|
} else {
|
||||||
|
// FIXME: linux only
|
||||||
|
enable_sock_opt(fd, ::libc::IP_MTU_DISCOVER, ::libc::IP_PMTUDISC_DO)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(socket)
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ use ::std::{sync::Arc, vec::Vec};
|
||||||
/// Information needed to reply after the key exchange
|
/// Information needed to reply after the key exchange
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AuthNeededInfo {
|
pub struct AuthNeededInfo {
|
||||||
/// Parsed handshake
|
/// Parsed handshake packet
|
||||||
pub handshake: Handshake,
|
pub handshake: Handshake,
|
||||||
/// hkdf generated from the handshake
|
/// hkdf generated from the handshake
|
||||||
pub hkdf: HkdfSha3,
|
pub hkdf: HkdfSha3,
|
||||||
|
@ -32,12 +32,10 @@ pub struct AuthNeededInfo {
|
||||||
/// Client information needed to fully establish the conenction
|
/// Client information needed to fully establish the conenction
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ClientConnectInfo {
|
pub struct ClientConnectInfo {
|
||||||
/// Parsed handshake
|
/// Parsed handshake packet
|
||||||
pub handshake: Handshake,
|
pub handshake: Handshake,
|
||||||
/// hkdf generated from the handshake
|
/// Connection
|
||||||
pub hkdf: HkdfSha3,
|
pub connection: Arc<Connection>,
|
||||||
/// cipher to be used in both directions
|
|
||||||
pub cipher_recv: CipherRecv,
|
|
||||||
}
|
}
|
||||||
/// Intermediate actions to be taken while parsing the handshake
|
/// Intermediate actions to be taken while parsing the handshake
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -182,9 +180,7 @@ impl Tracker {
|
||||||
return Err(handshake::Error::UnknownKeyID.into());
|
return Err(handshake::Error::UnknownKeyID.into());
|
||||||
}
|
}
|
||||||
let hshake = hshake.unwrap();
|
let hshake = hshake.unwrap();
|
||||||
let secret_recv = hshake.hkdf.get_secret(b"to_client");
|
let cipher_recv = &hshake.connection.cipher_recv;
|
||||||
let cipher_recv =
|
|
||||||
CipherRecv::new(hshake.cipher, secret_recv);
|
|
||||||
use crate::enc::sym::AAD;
|
use crate::enc::sym::AAD;
|
||||||
// no aad for now
|
// no aad for now
|
||||||
let aad = AAD(&mut []);
|
let aad = AAD(&mut []);
|
||||||
|
@ -202,8 +198,7 @@ impl Tracker {
|
||||||
return Ok(HandshakeAction::ClientConnect(
|
return Ok(HandshakeAction::ClientConnect(
|
||||||
ClientConnectInfo {
|
ClientConnectInfo {
|
||||||
handshake,
|
handshake,
|
||||||
hkdf: hshake.hkdf,
|
connection: hshake.connection,
|
||||||
cipher_recv,
|
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
139
src/lib.rs
139
src/lib.rs
|
@ -33,9 +33,12 @@ use ::tokio::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
connection::{
|
connection::{
|
||||||
handshake::{self, Handshake, HandshakeClient, HandshakeServer},
|
handshake::{
|
||||||
|
self, dirsync::DirSync, Handshake, HandshakeClient, HandshakeData,
|
||||||
|
HandshakeServer,
|
||||||
|
},
|
||||||
socket::{SocketList, UdpClient, UdpServer},
|
socket::{SocketList, UdpClient, UdpServer},
|
||||||
ConnList, Connection,
|
ConnList, Connection, IDSend,
|
||||||
},
|
},
|
||||||
enc::{
|
enc::{
|
||||||
asym,
|
asym,
|
||||||
|
@ -167,34 +170,13 @@ impl Fenrir {
|
||||||
self.dnssec = None;
|
self.dnssec = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable some common socket options. This is just the unsafe part
|
|
||||||
fn enable_sock_opt(
|
|
||||||
fd: ::std::os::fd::RawFd,
|
|
||||||
option: ::libc::c_int,
|
|
||||||
value: ::libc::c_int,
|
|
||||||
) -> ::std::io::Result<()> {
|
|
||||||
#[allow(unsafe_code)]
|
|
||||||
unsafe {
|
|
||||||
#[allow(trivial_casts)]
|
|
||||||
let val = &value as *const _ as *const ::libc::c_void;
|
|
||||||
let size = ::std::mem::size_of_val(&value) as ::libc::socklen_t;
|
|
||||||
// always clear the error bit before doing a new syscall
|
|
||||||
let _ = ::std::io::Error::last_os_error();
|
|
||||||
let ret =
|
|
||||||
::libc::setsockopt(fd, ::libc::SOL_SOCKET, option, val, size);
|
|
||||||
if ret != 0 {
|
|
||||||
return Err(::std::io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add all UDP sockets found in config
|
/// Add all UDP sockets found in config
|
||||||
/// and start listening for packets
|
/// and start listening for packets
|
||||||
async fn add_sockets(&self) -> ::std::io::Result<()> {
|
async fn add_sockets(&self) -> ::std::io::Result<()> {
|
||||||
let sockets = self.cfg.listen.iter().map(|s_addr| async {
|
let sockets = self.cfg.listen.iter().map(|s_addr| async {
|
||||||
let socket =
|
let socket =
|
||||||
::tokio::spawn(Self::bind_udp(s_addr.clone())).await??;
|
::tokio::spawn(connection::socket::bind_udp(s_addr.clone()))
|
||||||
|
.await??;
|
||||||
Ok(socket)
|
Ok(socket)
|
||||||
});
|
});
|
||||||
let sockets = ::futures::future::join_all(sockets).await;
|
let sockets = ::futures::future::join_all(sockets).await;
|
||||||
|
@ -218,32 +200,6 @@ impl Fenrir {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an async udp listener
|
|
||||||
async fn bind_udp(sock: SocketAddr) -> ::std::io::Result<UdpSocket> {
|
|
||||||
let socket = UdpSocket::bind(sock).await?;
|
|
||||||
|
|
||||||
use ::std::os::fd::AsRawFd;
|
|
||||||
let fd = socket.as_raw_fd();
|
|
||||||
// can be useful later on for reloads
|
|
||||||
Self::enable_sock_opt(fd, ::libc::SO_REUSEADDR, 1)?;
|
|
||||||
Self::enable_sock_opt(fd, ::libc::SO_REUSEPORT, 1)?;
|
|
||||||
|
|
||||||
// We will do path MTU discovery by ourselves,
|
|
||||||
// always set the "don't fragment" bit
|
|
||||||
if sock.is_ipv6() {
|
|
||||||
Self::enable_sock_opt(fd, ::libc::IPV6_DONTFRAG, 1)?;
|
|
||||||
} else {
|
|
||||||
// FIXME: linux only
|
|
||||||
Self::enable_sock_opt(
|
|
||||||
fd,
|
|
||||||
::libc::IP_MTU_DISCOVER,
|
|
||||||
::libc::IP_PMTUDISC_DO,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(socket)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run a dedicated loop to read packets on the listening socket
|
/// Run a dedicated loop to read packets on the listening socket
|
||||||
async fn listen_udp(
|
async fn listen_udp(
|
||||||
mut stop_working: ::tokio::sync::broadcast::Receiver<bool>,
|
mut stop_working: ::tokio::sync::broadcast::Receiver<bool>,
|
||||||
|
@ -350,9 +306,15 @@ impl Fenrir {
|
||||||
dirsync::{self, DirSync},
|
dirsync::{self, DirSync},
|
||||||
HandshakeData,
|
HandshakeData,
|
||||||
};
|
};
|
||||||
match authinfo.handshake.data {
|
let req;
|
||||||
HandshakeData::DirSync(ds) => match ds {
|
if let HandshakeData::DirSync(DirSync::Req(r)) =
|
||||||
DirSync::Req(req) => {
|
authinfo.handshake.data
|
||||||
|
{
|
||||||
|
req = r;
|
||||||
|
} else {
|
||||||
|
::tracing::error!("AuthInfo on non DS::Req");
|
||||||
|
return;
|
||||||
|
}
|
||||||
use dirsync::ReqInner;
|
use dirsync::ReqInner;
|
||||||
let req_data = match req.data {
|
let req_data = match req.data {
|
||||||
ReqInner::ClearText(req_data) => req_data,
|
ReqInner::ClearText(req_data) => req_data,
|
||||||
|
@ -373,9 +335,7 @@ impl Fenrir {
|
||||||
{
|
{
|
||||||
Ok(is_authenticated) => is_authenticated,
|
Ok(is_authenticated) => is_authenticated,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
::tracing::error!(
|
::tracing::error!("error in token auth");
|
||||||
"error in token auth"
|
|
||||||
);
|
|
||||||
// TODO: retry?
|
// TODO: retry?
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -391,29 +351,27 @@ impl Fenrir {
|
||||||
// Client has correctly authenticated
|
// Client has correctly authenticated
|
||||||
// TODO: contact the service, get the key and
|
// TODO: contact the service, get the key and
|
||||||
// connection ID
|
// connection ID
|
||||||
let srv_conn_id =
|
let srv_conn_id = connection::ID::new_rand(&self.rand);
|
||||||
connection::ID::new_rand(&self.rand);
|
let srv_secret = enc::sym::Secret::new_rand(&self.rand);
|
||||||
let srv_secret =
|
|
||||||
enc::sym::Secret::new_rand(&self.rand);
|
|
||||||
let head_len = req.cipher.nonce_len();
|
let head_len = req.cipher.nonce_len();
|
||||||
let tag_len = req.cipher.tag_len();
|
let tag_len = req.cipher.tag_len();
|
||||||
|
|
||||||
let raw_conn = Connection::new(
|
let mut raw_conn = Connection::new(
|
||||||
authinfo.hkdf,
|
authinfo.hkdf,
|
||||||
req.cipher,
|
req.cipher,
|
||||||
connection::Role::Server,
|
connection::Role::Server,
|
||||||
&self.rand,
|
&self.rand,
|
||||||
);
|
);
|
||||||
|
raw_conn.id_send = IDSend(req_data.id);
|
||||||
// track connection
|
// track connection
|
||||||
let auth_conn = {
|
let auth_conn = {
|
||||||
let mut lock =
|
let mut lock = self.connections.write().await;
|
||||||
self.connections.write().await;
|
|
||||||
lock.reserve_first(raw_conn)
|
lock.reserve_first(raw_conn)
|
||||||
};
|
};
|
||||||
|
|
||||||
let resp_data = dirsync::RespData {
|
let resp_data = dirsync::RespData {
|
||||||
client_nonce: req_data.nonce,
|
client_nonce: req_data.nonce,
|
||||||
id: auth_conn.id,
|
id: auth_conn.id_recv.0,
|
||||||
service_id: srv_conn_id,
|
service_id: srv_conn_id,
|
||||||
service_key: srv_secret,
|
service_key: srv_secret,
|
||||||
};
|
};
|
||||||
|
@ -427,9 +385,8 @@ impl Fenrir {
|
||||||
data: RespInner::ClearText(resp_data),
|
data: RespInner::ClearText(resp_data),
|
||||||
};
|
};
|
||||||
let offset_to_encrypt = resp.encrypted_offset();
|
let offset_to_encrypt = resp.encrypted_offset();
|
||||||
let encrypt_until = offset_to_encrypt
|
let encrypt_until =
|
||||||
+ resp.encrypted_length()
|
offset_to_encrypt + resp.encrypted_length() + tag_len.0;
|
||||||
+ tag_len.0;
|
|
||||||
let resp_handshake = Handshake::new(
|
let resp_handshake = Handshake::new(
|
||||||
HandshakeData::DirSync(DirSync::Resp(resp)),
|
HandshakeData::DirSync(DirSync::Resp(resp)),
|
||||||
);
|
);
|
||||||
|
@ -438,33 +395,45 @@ impl Fenrir {
|
||||||
id: ID::new_handshake(),
|
id: ID::new_handshake(),
|
||||||
data: PacketData::Handshake(resp_handshake),
|
data: PacketData::Handshake(resp_handshake),
|
||||||
};
|
};
|
||||||
let mut raw_out =
|
let mut raw_out = Vec::<u8>::with_capacity(packet.len());
|
||||||
Vec::<u8>::with_capacity(packet.len());
|
packet.serialize(head_len, tag_len, &mut raw_out);
|
||||||
packet.serialize(
|
|
||||||
head_len,
|
|
||||||
tag_len,
|
|
||||||
&mut raw_out,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Err(e) = auth_conn.cipher_send.encrypt(
|
if let Err(e) = auth_conn.cipher_send.encrypt(
|
||||||
aad,
|
aad,
|
||||||
&mut raw_out
|
&mut raw_out[offset_to_encrypt..encrypt_until],
|
||||||
[offset_to_encrypt..encrypt_until],
|
|
||||||
) {
|
) {
|
||||||
::tracing::error!("can't encrypt: {:?}", e);
|
::tracing::error!("can't encrypt: {:?}", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.send_packet(raw_out, udp.src, udp.dst)
|
self.send_packet(raw_out, udp.src, udp.dst).await;
|
||||||
.await;
|
return;
|
||||||
}
|
}
|
||||||
DirSync::Resp(resp) => {
|
HandshakeAction::ClientConnect(mut cci) => {
|
||||||
todo!()
|
let ds_resp;
|
||||||
|
if let HandshakeData::DirSync(DirSync::Resp(resp)) =
|
||||||
|
cci.handshake.data
|
||||||
|
{
|
||||||
|
ds_resp = resp;
|
||||||
|
} else {
|
||||||
|
::tracing::error!("ClientConnect on non DS::Resp");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
_ => {
|
// track connection
|
||||||
todo!()
|
use handshake::dirsync;
|
||||||
}
|
let resp_data;
|
||||||
},
|
if let dirsync::RespInner::ClearText(r_data) = ds_resp.data
|
||||||
|
{
|
||||||
|
resp_data = r_data;
|
||||||
|
} else {
|
||||||
|
::tracing::error!(
|
||||||
|
"ClientConnect on non DS::Resp::ClearText"
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// FIXME: conn tracking and arc counting
|
||||||
|
let conn = Arc::get_mut(&mut cci.connection).unwrap();
|
||||||
|
conn.id_send = IDSend(resp_data.id);
|
||||||
|
todo!();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue