More work on Dirsync request sending

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2023-06-05 09:18:32 +02:00
parent 9634fbba31
commit 289c6c318e
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
10 changed files with 302 additions and 117 deletions

View File

@ -16,9 +16,17 @@ impl From<[u8; 16]> for UserID {
impl UserID { impl UserID {
/// New random user id /// New random user id
pub fn new(rand: &Random) -> Self { pub fn new(rand: &Random) -> Self {
let mut ret = Self([0; 16]); use ::core::mem::MaybeUninit;
rand.fill(&mut ret.0); let mut out: MaybeUninit<[u8; 16]> = MaybeUninit::uninit();
ret #[allow(unsafe_code)]
unsafe {
let _ = rand.fill(out.assume_init_mut());
Self(out.assume_init())
}
}
/// Anonymous user id
pub fn new_anonymous() -> Self {
UserID([0; 16])
} }
/// length of the User ID in bytes /// length of the User ID in bytes
pub const fn len() -> usize { pub const fn len() -> usize {
@ -31,6 +39,16 @@ impl UserID {
pub struct Token([u8; 32]); pub struct Token([u8; 32]);
impl Token { impl Token {
/// New random token, anonymous should not check this anyway
pub fn new_anonymous(rand: &Random) -> Self {
use ::core::mem::MaybeUninit;
let mut out: MaybeUninit<[u8; 32]> = MaybeUninit::uninit();
#[allow(unsafe_code)]
unsafe {
let _ = rand.fill(out.assume_init_mut());
Self(out.assume_init())
}
}
/// length of the token in bytes /// length of the token in bytes
pub const fn len() -> usize { pub const fn len() -> usize {
32 32
@ -68,7 +86,7 @@ pub type TokenChecker =
/// further limit to a "safe" subset of utf8 /// further limit to a "safe" subset of utf8
// SECURITY: TODO: limit to a subset of utf8 // SECURITY: TODO: limit to a subset of utf8
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Domain(String); pub struct Domain(pub String);
impl TryFrom<&[u8]> for Domain { impl TryFrom<&[u8]> for Domain {
type Error = (); type Error = ();

View File

@ -3,11 +3,15 @@
pub mod dirsync; pub mod dirsync;
use crate::{ use crate::{
connection::{self, ProtocolVersion}, auth::ServiceID,
enc::sym::{HeadLen, TagLen}, connection::{self, Connection, IDRecv, ProtocolVersion},
enc::{
asym::{KeyID, PrivKey, PubKey},
sym::{HeadLen, TagLen},
},
}; };
use ::num_traits::FromPrimitive; use ::num_traits::FromPrimitive;
use ::std::rc::Rc; use ::std::{collections::VecDeque, rc::Rc};
/// Handshake errors /// Handshake errors
#[derive(::thiserror::Error, Debug, Copy, Clone)] #[derive(::thiserror::Error, Debug, Copy, Clone)]
@ -32,6 +36,9 @@ pub enum Error {
/// Could not generate Keys /// Could not generate Keys
#[error("Key generation failed")] #[error("Key generation failed")]
KeyGeneration, KeyGeneration,
/// Too many client handshakes currently running
#[error("Too many client handshakes")]
TooManyClientHandshakes,
} }
/// List of possible handshakes /// List of possible handshakes
@ -66,20 +73,108 @@ impl TryFrom<&str> for HandshakeID {
} }
pub(crate) struct HandshakeServer { pub(crate) struct HandshakeServer {
pub id: crate::enc::asym::KeyID, pub id: KeyID,
pub key: crate::enc::asym::PrivKey, pub key: PrivKey,
} }
#[derive(Clone)]
pub(crate) struct HandshakeClient { pub(crate) struct HandshakeClient {
pub id: crate::enc::asym::KeyID, pub id: KeyID,
pub key: crate::enc::asym::PrivKey, pub key: PrivKey,
pub service_id: crate::auth::ServiceID, pub service_id: ServiceID,
pub service_conn_id: connection::IDRecv, pub service_conn_id: IDRecv,
pub connection: Rc<crate::connection::Connection>, pub connection: Connection,
pub timeout: Rc<u32>, pub timeout: Rc<u32>,
} }
/// Tracks the keys used by the client and the handshake
/// they are associated with
pub(crate) struct HandshakeClientList {
used: Vec<::bitmaps::Bitmap<1024>>, // index = KeyID
keys: Vec<Option<(PrivKey, PubKey)>>,
list: Vec<Option<HandshakeClient>>,
}
impl HandshakeClientList {
pub(crate) fn new() -> Self {
Self {
used: [::bitmaps::Bitmap::<1024>::new()].to_vec(),
keys: Vec::with_capacity(16),
list: Vec::with_capacity(16),
}
}
pub(crate) fn get(&self, id: KeyID) -> Option<&HandshakeClient> {
if id.0 as usize >= self.list.len() {
return None;
}
self.list[id.0 as usize].as_ref()
}
pub(crate) fn remove(&mut self, id: KeyID) -> Option<HandshakeClient> {
if id.0 as usize >= self.list.len() {
return None;
}
let used_vec_idx = id.0 as usize / 1024;
let used_bitmap_idx = id.0 as usize % 1024;
let used_iter = match self.used.get_mut(used_vec_idx) {
Some(used_iter) => used_iter,
None => return None,
};
used_iter.set(used_bitmap_idx, false);
self.keys[id.0 as usize] = None;
let mut owned = None;
::core::mem::swap(&mut self.list[id.0 as usize], &mut owned);
owned
}
pub(crate) fn add(
&mut self,
priv_key: PrivKey,
pub_key: PubKey,
service_id: ServiceID,
service_conn_id: IDRecv,
connection: Connection,
) -> Result<(KeyID, &HandshakeClient), ()> {
let maybe_free_key_idx =
self.used.iter().enumerate().find_map(|(idx, bmap)| {
match bmap.first_false_index() {
Some(false_idx) => Some(((idx * 1024), false_idx)),
None => None,
}
});
let free_key_idx = match maybe_free_key_idx {
Some((idx, false_idx)) => {
let free_key_idx = idx * 1024 + false_idx;
if free_key_idx > KeyID::MAX as usize {
return Err(());
}
self.used[idx].set(false_idx, true);
free_key_idx
}
None => {
let mut bmap = ::bitmaps::Bitmap::<1024>::new();
bmap.set(0, true);
self.used.push(bmap);
self.used.len() * 1024
}
};
if self.keys.len() >= free_key_idx {
self.keys.push(None);
self.list.push(None);
}
self.keys[free_key_idx] = Some((priv_key.clone(), pub_key));
self.list[free_key_idx] = Some(HandshakeClient {
id: KeyID(free_key_idx as u16),
key: priv_key,
service_id,
service_conn_id,
connection,
timeout: Rc::new(0),
});
Ok((
KeyID(free_key_idx as u16),
self.list[free_key_idx].as_ref().unwrap(),
))
}
}
/// Parsed handshake /// Parsed handshake
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum HandshakeData { pub enum HandshakeData {

View File

@ -132,10 +132,7 @@ impl ConnList {
} }
/// Only *Reserve* a connection, /// Only *Reserve* a connection,
/// without actually tracking it in self.connections /// without actually tracking it in self.connections
pub(crate) fn reserve_first( pub(crate) fn reserve_first(&mut self) -> IDRecv {
&mut self,
mut conn: Connection,
) -> Rc<Connection> {
// uhm... bad things are going on here: // uhm... bad things are going on here:
// * id must be initialized, but only because: // * id must be initialized, but only because:
// * rust does not understand that after the `!found` id is always // * rust does not understand that after the `!found` id is always
@ -173,9 +170,7 @@ impl ConnList {
let actual_id = ((id_in_thread as u64) * (self.thread_id.total as u64)) let actual_id = ((id_in_thread as u64) * (self.thread_id.total as u64))
+ (self.thread_id.id as u64); + (self.thread_id.id as u64);
let new_id = IDRecv(ID::new_u64(actual_id)); let new_id = IDRecv(ID::new_u64(actual_id));
conn.id_recv = new_id; new_id
// Return the new connection without tracking it
Rc::new(conn)
} }
/// NOTE: does NOT check if the connection has been previously reserved! /// NOTE: does NOT check if the connection has been previously reserved!
pub(crate) fn track(&mut self, conn: Rc<Connection>) -> Result<(), ()> { pub(crate) fn track(&mut self, conn: Rc<Connection>) -> Result<(), ()> {

View File

@ -7,6 +7,8 @@ use ::trust_dns_resolver::TokioAsyncResolver;
pub mod record; pub mod record;
pub use record::Record; pub use record::Record;
use crate::auth::Domain;
/// Common errors for Dnssec setup and usage /// Common errors for Dnssec setup and usage
#[derive(::thiserror::Error, Debug)] #[derive(::thiserror::Error, Debug)]
pub enum Error { pub enum Error {
@ -88,10 +90,10 @@ impl Dnssec {
} }
const TXT_RECORD_START: &str = "v=Fenrir1 "; const TXT_RECORD_START: &str = "v=Fenrir1 ";
/// Get the fenrir data for a domain /// Get the fenrir data for a domain
pub async fn resolv(&self, domain: &str) -> ::std::io::Result<String> { pub async fn resolv(&self, domain: &Domain) -> ::std::io::Result<String> {
use ::trust_dns_client::rr::Name; use ::trust_dns_client::rr::Name;
let fqdn_str = "_fenrir.".to_owned() + domain; let fqdn_str = "_fenrir.".to_owned() + &domain.0;
::tracing::debug!("Resolving: {}", fqdn_str); ::tracing::debug!("Resolving: {}", fqdn_str);
let fqdn = Name::from_utf8(&fqdn_str)?; let fqdn = Name::from_utf8(&fqdn_str)?;
let answers = self.resolver.txt_lookup(fqdn).await?; let answers = self.resolver.txt_lookup(fqdn).await?;

View File

@ -17,6 +17,8 @@ impl KeyID {
pub const fn len() -> usize { pub const fn len() -> usize {
2 2
} }
/// Maximum possible KeyID
pub const MAX: u16 = u16::MAX;
/// Serialize into raw bytes /// Serialize into raw bytes
pub fn serialize(&self, out: &mut [u8; KeyID::len()]) { pub fn serialize(&self, out: &mut [u8; KeyID::len()]) {
out.copy_from_slice(&self.0.to_le_bytes()); out.copy_from_slice(&self.0.to_le_bytes());

View File

@ -51,6 +51,12 @@ impl Hkdf {
Hkdf::Sha3(sha3) => sha3.get_secret(context), Hkdf::Sha3(sha3) => sha3.get_secret(context),
} }
} }
/// get the kind of this Hkdf
pub fn kind(&self) -> HkdfKind {
match self {
Hkdf::Sha3(_) => HkdfKind::Sha3,
}
}
} }
// Hack & tricks: // Hack & tricks:

View File

@ -39,7 +39,7 @@ impl CipherKind {
/// Additional Authenticated Data /// Additional Authenticated Data
#[derive(Debug)] #[derive(Debug)]
pub struct AAD<'a>(pub &'a mut [u8]); pub struct AAD<'a>(pub &'a [u8]);
/// Cipher direction, to make sure we don't reuse the same cipher /// Cipher direction, to make sure we don't reuse the same cipher
/// for both decrypting and encrypting /// for both decrypting and encrypting

View File

@ -5,20 +5,24 @@
pub(crate) mod worker; pub(crate) mod worker;
use crate::{ use crate::{
auth, auth::ServiceID,
connection::{ connection::{
self, self,
handshake::{self, Handshake, HandshakeClient, HandshakeServer}, handshake::{
Connection, self, Handshake, HandshakeClient, HandshakeClientList,
HandshakeServer,
},
Connection, IDRecv,
}, },
enc::{ enc::{
self, asym, self,
asym::{self, KeyID, PrivKey, PubKey},
hkdf::{Hkdf, HkdfKind}, hkdf::{Hkdf, HkdfKind},
sym::{CipherKind, CipherRecv}, sym::{CipherKind, CipherRecv},
}, },
Error, Error,
}; };
use ::std::{rc::Rc, vec::Vec}; use ::std::vec::Vec;
/// Information needed to reply after the key exchange /// Information needed to reply after the key exchange
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -35,13 +39,13 @@ pub(crate) struct AuthNeededInfo {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct ClientConnectInfo { pub(crate) struct ClientConnectInfo {
/// The service ID that we are connecting to /// The service ID that we are connecting to
pub service_id: auth::ServiceID, pub service_id: ServiceID,
/// The service ID that we are connecting to /// The service ID that we are connecting to
pub service_connection_id: connection::IDRecv, pub service_connection_id: IDRecv,
/// Parsed handshake packet /// Parsed handshake packet
pub handshake: Handshake, pub handshake: Handshake,
/// Connection /// Connection
pub connection: Rc<Connection>, pub connection: Connection,
} }
/// Intermediate actions to be taken while parsing the handshake /// Intermediate actions to be taken while parsing the handshake
#[derive(Debug)] #[derive(Debug)]
@ -63,11 +67,11 @@ pub(crate) struct ThreadTracker {
pub id: u16, pub id: u16,
} }
/// Async free but thread safe tracking of handhsakes and conenctions /// Tracking of handhsakes and conenctions
/// Note that we have multiple Handshake trackers, pinned to different cores /// Note that we have multiple Handshake trackers, pinned to different cores
/// Each of them will handle a subset of all handshakes. /// Each of them will handle a subset of all handshakes.
/// Each handshake is routed to a different tracker with: /// Each handshake is routed to a different tracker by checking
/// (udp_src_sender_port % total_threads) - 1 /// core = (udp_src_sender_port % total_threads) - 1
pub(crate) struct HandshakeTracker { pub(crate) struct HandshakeTracker {
thread_id: ThreadTracker, thread_id: ThreadTracker,
key_exchanges: Vec<(asym::KeyKind, asym::KeyExchangeKind)>, key_exchanges: Vec<(asym::KeyKind, asym::KeyExchangeKind)>,
@ -75,12 +79,8 @@ pub(crate) struct HandshakeTracker {
/// ephemeral keys used server side in key exchange /// ephemeral keys used server side in key exchange
keys_srv: Vec<HandshakeServer>, keys_srv: Vec<HandshakeServer>,
/// ephemeral keys used client side in key exchange /// ephemeral keys used client side in key exchange
hshake_cli: Vec<HandshakeClient>, hshake_cli: HandshakeClientList,
} }
#[allow(unsafe_code)]
unsafe impl Send for HandshakeTracker {}
#[allow(unsafe_code)]
unsafe impl Sync for HandshakeTracker {}
impl HandshakeTracker { impl HandshakeTracker {
pub(crate) fn new(thread_id: ThreadTracker) -> Self { pub(crate) fn new(thread_id: ThreadTracker) -> Self {
@ -89,9 +89,25 @@ impl HandshakeTracker {
ciphers: Vec::new(), ciphers: Vec::new(),
key_exchanges: Vec::new(), key_exchanges: Vec::new(),
keys_srv: Vec::new(), keys_srv: Vec::new(),
hshake_cli: Vec::new(), hshake_cli: HandshakeClientList::new(),
} }
} }
pub(crate) fn new_client(
&mut self,
priv_key: PrivKey,
pub_key: PubKey,
service_id: ServiceID,
service_conn_id: IDRecv,
connection: Connection,
) -> Result<(KeyID, &HandshakeClient), ()> {
self.hshake_cli.add(
priv_key,
pub_key,
service_id,
service_conn_id,
connection,
)
}
pub(crate) fn recv_handshake( pub(crate) fn recv_handshake(
&mut self, &mut self,
mut handshake: Handshake, mut handshake: Handshake,
@ -105,7 +121,6 @@ impl HandshakeTracker {
if let Some(h_k) = if let Some(h_k) =
self.keys_srv.iter().find(|k| k.id == req.key_id) self.keys_srv.iter().find(|k| k.id == req.key_id)
{ {
use enc::asym::PrivKey;
// Directory synchronized can only use keys // Directory synchronized can only use keys
// for key exchange, not signing keys // for key exchange, not signing keys
if let PrivKey::Exchange(k) = &h_k.key { if let PrivKey::Exchange(k) = &h_k.key {
@ -175,20 +190,9 @@ impl HandshakeTracker {
})); }));
} }
DirSync::Resp(resp) => { DirSync::Resp(resp) => {
let hshake_idx = { let hshake = match self.hshake_cli.get(resp.client_key_id) {
match self Some(hshake) => hshake,
.hshake_cli None => {
.iter()
.position(|h| h.id == resp.client_key_id)
{
Some(h) => Some(h.clone()),
None => None,
}
};
let hshake_idx = {
if let Some(real_idx) = hshake_idx {
real_idx
} else {
::tracing::debug!( ::tracing::debug!(
"No such client key id: {:?}", "No such client key id: {:?}",
resp.client_key_id resp.client_key_id
@ -196,7 +200,6 @@ impl HandshakeTracker {
return Err(handshake::Error::UnknownKeyID.into()); return Err(handshake::Error::UnknownKeyID.into());
} }
}; };
let hshake = &self.hshake_cli[hshake_idx];
let cipher_recv = &hshake.connection.cipher_recv; let cipher_recv = &hshake.connection.cipher_recv;
use crate::enc::sym::AAD; use crate::enc::sym::AAD;
// no aad for now // no aad for now
@ -212,14 +215,8 @@ impl HandshakeTracker {
return Err(handshake::Error::Key(e).into()); return Err(handshake::Error::Key(e).into());
} }
} }
// we can remove the handshake from the list let hshake =
let hshake: HandshakeClient = { self.hshake_cli.remove(resp.client_key_id).unwrap();
let len = self.hshake_cli.len();
if (hshake_idx + 1) != len {
self.hshake_cli.swap(hshake_idx, len - 1);
}
self.hshake_cli.pop().unwrap()
};
return Ok(HandshakeAction::ClientConnect( return Ok(HandshakeAction::ClientConnect(
ClientConnectInfo { ClientConnectInfo {
service_id: hshake.service_id, service_id: hshake.service_id,

View File

@ -1,6 +1,6 @@
//! Worker thread implementation //! Worker thread implementation
use crate::{ use crate::{
auth::{ServiceID, TokenChecker}, auth::{Domain, ServiceID, Token, TokenChecker, UserID},
config::Config, config::Config,
connection::{ connection::{
self, self,
@ -14,10 +14,9 @@ use crate::{
}, },
dnssec, dnssec,
enc::{ enc::{
asym::{self, PrivKey, PubKey}, asym::{PrivKey, PubKey},
hkdf::{self, Hkdf, HkdfKind}, hkdf::{self, Hkdf, HkdfKind},
sym::{self}, sym, Random, Secret,
Random, Secret,
}, },
inner::{HandshakeAction, HandshakeTracker, ThreadTracker}, inner::{HandshakeAction, HandshakeTracker, ThreadTracker},
}; };
@ -36,17 +35,19 @@ pub(crate) struct RawUdp {
pub packet: Packet, pub packet: Packet,
} }
pub(crate) struct ConnectInfo {
pub answer: oneshot::Sender<Result<(PubKey, IDSend), crate::Error>>,
pub resolved: dnssec::Record,
pub service_id: ServiceID,
pub domain: Domain,
// TODO: UserID, Token information
}
pub(crate) enum Work { pub(crate) enum Work {
/// ask the thread to report to the main thread the total number of /// ask the thread to report to the main thread the total number of
/// connections present /// connections present
CountConnections(oneshot::Sender<usize>), CountConnections(oneshot::Sender<usize>),
Connect( Connect(ConnectInfo),
(
oneshot::Sender<Result<(PubKey, IDSend), crate::Error>>,
dnssec::Record,
ServiceID,
),
),
Recv(RawUdp), Recv(RawUdp),
} }
pub(crate) enum WorkAnswer { pub(crate) enum WorkAnswer {
@ -162,13 +163,13 @@ impl Worker {
let conn_num = self.connections.len(); let conn_num = self.connections.len();
let _ = sender.send(conn_num); let _ = sender.send(conn_num);
} }
Work::Connect((send_res, dnssec_record, _service_id)) => { Work::Connect(conn_info) => {
// PERF: geolocation // PERF: geolocation
// Find the first destination with a coherent // Find the first destination with a coherent
// pubkey/key exchange // pubkey/key exchange
let destination = let destination =
dnssec_record.addresses.iter().find_map(|addr| { conn_info.resolved.addresses.iter().find_map(|addr| {
if addr if addr
.handshake_ids .handshake_ids
.iter() .iter()
@ -187,7 +188,8 @@ impl Worker {
// *we* support // *we* support
for idx in addr.public_key_idx.iter() { for idx in addr.public_key_idx.iter() {
let key_supported_k_x = let key_supported_k_x =
dnssec_record.public_keys[idx.0 as usize] conn_info.resolved.public_keys
[idx.0 as usize]
.1 .1
.kind() .kind()
.key_exchanges(); .key_exchanges();
@ -200,7 +202,7 @@ impl Worker {
Some(exchange) => { Some(exchange) => {
return Some(( return Some((
addr, addr,
dnssec_record.public_keys conn_info.resolved.public_keys
[idx.0 as usize], [idx.0 as usize],
exchange.clone(), exchange.clone(),
)) ))
@ -214,7 +216,9 @@ impl Worker {
Some((addr, key, exchange)) => (addr, key, exchange), Some((addr, key, exchange)) => (addr, key, exchange),
None => { None => {
let _ = let _ =
send_res.send(Err(crate::Error::Resolution( conn_info
.answer
.send(Err(crate::Error::Resolution(
"No selectable address and key combination" "No selectable address and key combination"
.to_owned(), .to_owned(),
))); )));
@ -223,11 +227,11 @@ impl Worker {
}; };
let hkdf_selected = match hkdf::client_select_hkdf( let hkdf_selected = match hkdf::client_select_hkdf(
&self.cfg, &self.cfg,
&dnssec_record.hkdfs, &conn_info.resolved.hkdfs,
) { ) {
Some(hkdf_selected) => hkdf_selected, Some(hkdf_selected) => hkdf_selected,
None => { None => {
let _ = send_res.send(Err( let _ = conn_info.answer.send(Err(
handshake::Error::Negotiation.into(), handshake::Error::Negotiation.into(),
)); ));
continue 'mainloop; continue 'mainloop;
@ -235,23 +239,24 @@ impl Worker {
}; };
let cipher_selected = match sym::client_select_cipher( let cipher_selected = match sym::client_select_cipher(
&self.cfg, &self.cfg,
&dnssec_record.ciphers, &conn_info.resolved.ciphers,
) { ) {
Some(cipher_selected) => cipher_selected, Some(cipher_selected) => cipher_selected,
None => { None => {
let _ = send_res.send(Err( let _ = conn_info.answer.send(Err(
handshake::Error::Negotiation.into(), handshake::Error::Negotiation.into(),
)); ));
continue 'mainloop; continue 'mainloop;
} }
}; };
// FIXME: save KeyID
let (priv_key, pub_key) = let (priv_key, pub_key) =
match exchange.new_keypair(&self.rand) { match exchange.new_keypair(&self.rand) {
Ok(pair) => pair, Ok(pair) => pair,
Err(_) => { Err(_) => {
::tracing::error!("Failed to generate keys"); ::tracing::error!("Failed to generate keys");
let _ = send_res.send(Err( let _ = conn_info.answer.send(Err(
handshake::Error::KeyGeneration.into(), handshake::Error::KeyGeneration.into(),
)); ));
continue 'mainloop; continue 'mainloop;
@ -266,7 +271,7 @@ impl Worker {
::tracing::warn!( ::tracing::warn!(
"Could not run the key exchange" "Could not run the key exchange"
); );
let _ = send_res.send(Err( let _ = conn_info.answer.send(Err(
handshake::Error::Negotiation.into(), handshake::Error::Negotiation.into(),
)); ));
continue 'mainloop; continue 'mainloop;
@ -279,25 +284,79 @@ impl Worker {
// are PubKey::Exchange // are PubKey::Exchange
unreachable!() unreachable!()
} }
let mut conn = Connection::new(
hkdf,
cipher_selected,
connection::Role::Client,
&self.rand,
);
let auth_recv_id = self.connections.reserve_first();
let service_conn_id = self.connections.reserve_first();
conn.id_recv = auth_recv_id;
let (client_key_id, hshake) = match self
.handshakes
.new_client(
PrivKey::Exchange(priv_key),
PubKey::Exchange(pub_key),
conn_info.service_id,
service_conn_id,
conn,
) {
Ok((client_key_id, hshake)) => (client_key_id, hshake),
Err(_) => {
::tracing::warn!("Too many client handshakes");
let _ = conn_info.answer.send(Err(
handshake::Error::TooManyClientHandshakes
.into(),
));
continue 'mainloop;
}
};
// build request // build request
/* let auth_info = dirsync::AuthInfo {
user: UserID::new_anonymous(),
token: Token::new_anonymous(&self.rand),
service_id: conn_info.service_id,
domain: conn_info.domain,
};
let req_data = dirsync::ReqData { let req_data = dirsync::ReqData {
nonce: dirsync::Nonce::new(&self.rand), nonce: dirsync::Nonce::new(&self.rand),
client_key_id: client_key_id,
id: auth_recv_id.0,
auth: auth_info,
}; };
let req = dirsync::Req { let req = dirsync::Req {
key_id: key.0, key_id: key.0,
exchange, exchange,
hkdf, hkdf: hkdf_selected,
cipher, cipher: cipher_selected,
exchange_key: client_pub_key, exchange_key: pub_key,
data: 42, data: dirsync::ReqInner::ClearText(req_data),
}; };
*/ let mut raw = Vec::<u8>::with_capacity(req.len());
req.serialize(
cipher_selected.nonce_len(),
cipher_selected.tag_len(),
&mut raw[..],
);
// encrypt
let encrypt_start = req.encrypted_offset();
let encrypt_end = encrypt_start + req.encrypted_length();
if let Err(e) = hshake.connection.cipher_send.encrypt(
sym::AAD(&[]),
&mut raw[encrypt_start..encrypt_end],
) {
::tracing::error!("Can't encrypt DirSync Request");
let _ = conn_info.answer.send(Err(e.into()));
continue 'mainloop;
}
// start timeout // start timeout
// send packet // send packeti
//self.send_packet(raw,
todo!() todo!()
} }
@ -395,15 +454,16 @@ impl Worker {
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 mut raw_conn = Connection::new( let mut auth_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); auth_conn.id_send = IDSend(req_data.id);
// track connection // track connection
let auth_conn = self.connections.reserve_first(raw_conn); let auth_id_recv = self.connections.reserve_first();
auth_conn.id_recv = auth_id_recv;
let resp_data = dirsync::RespData { let resp_data = dirsync::RespData {
client_nonce: req_data.nonce, client_nonce: req_data.nonce,
@ -444,7 +504,7 @@ impl Worker {
self.send_packet(raw_out, udp.src, udp.dst).await; self.send_packet(raw_out, udp.src, udp.dst).await;
return; return;
} }
HandshakeAction::ClientConnect(mut cci) => { HandshakeAction::ClientConnect(cci) => {
let ds_resp; let ds_resp;
if let HandshakeData::DirSync(DirSync::Resp(resp)) = if let HandshakeData::DirSync(DirSync::Resp(resp)) =
cci.handshake.data cci.handshake.data
@ -465,17 +525,17 @@ impl Worker {
); );
return; return;
} }
{ let mut conn = cci.connection;
let conn = Rc::get_mut(&mut cci.connection).unwrap(); conn.id_send = IDSend(resp_data.id);
conn.id_send = IDSend(resp_data.id); let id_recv = conn.id_recv;
} let cipher = conn.cipher_recv.kind();
// track the connection to the authentication server // track the connection to the authentication server
if self.connections.track(cci.connection.clone()).is_err() { if self.connections.track(Rc::new(conn)).is_err() {
self.connections.delete(cci.connection.id_recv); ::tracing::error!("Could not track new connection");
self.connections.delete(id_recv);
return;
} }
if cci.connection.id_recv.0 if id_recv.0 == resp_data.service_connection_id {
== resp_data.service_connection_id
{
// the user asked a single connection // the user asked a single connection
// to the authentication server, without any additional // to the authentication server, without any additional
// service. No more connections to setup // service. No more connections to setup
@ -492,7 +552,7 @@ impl Worker {
); );
let mut service_connection = Connection::new( let mut service_connection = Connection::new(
hkdf, hkdf,
cci.connection.cipher_recv.kind(), cipher,
connection::Role::Client, connection::Role::Client,
&self.rand, &self.rand,
); );

View File

@ -22,17 +22,16 @@ mod inner;
use ::std::{sync::Arc, vec::Vec}; use ::std::{sync::Arc, vec::Vec};
use ::tokio::{net::UdpSocket, sync::Mutex}; use ::tokio::{net::UdpSocket, sync::Mutex};
use auth::ServiceID;
use crate::{ use crate::{
auth::TokenChecker, auth::{Domain, ServiceID, TokenChecker},
connection::{ connection::{
handshake, handshake,
socket::{SocketList, UdpClient, UdpServer}, socket::{SocketList, UdpClient, UdpServer},
AuthServerConnections, Packet, AuthServerConnections, Packet,
}, },
inner::{ inner::{
worker::{RawUdp, Work, Worker}, worker::{ConnectInfo, RawUdp, Work, Worker},
ThreadTracker, ThreadTracker,
}, },
}; };
@ -62,6 +61,9 @@ pub enum Error {
/// Resolution problems. wrong or incomplete DNSSEC data /// Resolution problems. wrong or incomplete DNSSEC data
#[error("DNSSEC resolution: {0}")] #[error("DNSSEC resolution: {0}")]
Resolution(String), Resolution(String),
/// Wrapper on encryption errors
#[error("Encrypt: {0}")]
Encrypt(enc::Error),
} }
/// Instance of a fenrir endpoint /// Instance of a fenrir endpoint
@ -232,7 +234,7 @@ impl Fenrir {
Ok(()) Ok(())
} }
/// Get the raw TXT record of a Fenrir domain /// Get the raw TXT record of a Fenrir domain
pub async fn resolv_txt(&self, domain: &str) -> Result<String, Error> { pub async fn resolv_txt(&self, domain: &Domain) -> Result<String, Error> {
match &self.dnssec { match &self.dnssec {
Some(dnssec) => Ok(dnssec.resolv(domain).await?), Some(dnssec) => Ok(dnssec.resolv(domain).await?),
None => Err(Error::NotInitialized), None => Err(Error::NotInitialized),
@ -240,7 +242,10 @@ impl Fenrir {
} }
/// Get the raw TXT record of a Fenrir domain /// Get the raw TXT record of a Fenrir domain
pub async fn resolv(&self, domain: &str) -> Result<dnssec::Record, Error> { pub async fn resolv(
&self,
domain: &Domain,
) -> Result<dnssec::Record, Error> {
let record_str = self.resolv_txt(domain).await?; let record_str = self.resolv_txt(domain).await?;
Ok(dnssec::Dnssec::parse_txt_record(&record_str)?) Ok(dnssec::Dnssec::parse_txt_record(&record_str)?)
} }
@ -248,7 +253,7 @@ impl Fenrir {
/// Connect to a service /// Connect to a service
pub async fn connect( pub async fn connect(
&self, &self,
domain: &str, domain: &Domain,
service: ServiceID, service: ServiceID,
) -> Result<(), Error> { ) -> Result<(), Error> {
let resolved = self.resolv(domain).await?; let resolved = self.resolv(domain).await?;
@ -310,7 +315,12 @@ impl Fenrir {
// and tell that thread to connect somewhere // and tell that thread to connect somewhere
let (send, recv) = ::tokio::sync::oneshot::channel(); let (send, recv) = ::tokio::sync::oneshot::channel();
let _ = self._thread_work[thread_idx] let _ = self._thread_work[thread_idx]
.send(Work::Connect((send, resolved.clone(), service))) .send(Work::Connect(ConnectInfo {
answer: send,
resolved: resolved.clone(),
service_id: service,
domain: domain.clone(),
}))
.await; .await;
match recv.await { match recv.await {