Stream stubs, start using namespaces as intended
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
376e8fb833
commit
e1aa3ef074
24
flake.lock
24
flake.lock
|
@ -5,11 +5,11 @@
|
|||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681202837,
|
||||
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||
"lastModified": 1685518550,
|
||||
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -38,11 +38,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1684922889,
|
||||
"narHash": "sha256-l0WZAmln8959O7RdYUJ3gnAIM9OPKFLKHKGX4q+Blrk=",
|
||||
"lastModified": 1686921029,
|
||||
"narHash": "sha256-J1bX9plPCFhTSh6E3TWn9XSxggBh/zDD4xigyaIQBy8=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "04aaf8511678a0d0f347fdf1e8072fe01e4a509e",
|
||||
"rev": "c7ff1b9b95620ce8728c0d7bd501c458e6da9e04",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -54,11 +54,11 @@
|
|||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1684844536,
|
||||
"narHash": "sha256-M7HhXYVqAuNb25r/d3FOO0z4GxPqDIZp5UjHFbBgw0Q=",
|
||||
"lastModified": 1686960236,
|
||||
"narHash": "sha256-AYCC9rXNLpUWzD9hm+askOfpliLEC9kwAo7ITJc4HIw=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d30264c2691128adc261d7c9388033645f0e742b",
|
||||
"rev": "04af42f3b31dba0ef742d254456dc4c14eedac86",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -98,11 +98,11 @@
|
|||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1684894917,
|
||||
"narHash": "sha256-kwKCfmliHIxKuIjnM95TRcQxM/4AAEIZ+4A9nDJ6cJs=",
|
||||
"lastModified": 1687055571,
|
||||
"narHash": "sha256-UvLoO6u5n9TzY80BpM4DaacxvyJl7u9mm9CA72d309g=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "9ea38d547100edcf0da19aaebbdffa2810585495",
|
||||
"rev": "2de557c780dcb127128ae987fca9d6c2b0d7dc0f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
connection::{
|
||||
self,
|
||||
handshake::{self, Error, Handshake},
|
||||
Connection, IDRecv, IDSend,
|
||||
Conn, IDRecv, IDSend,
|
||||
},
|
||||
enc::{
|
||||
self,
|
||||
|
@ -29,7 +29,7 @@ pub(crate) type ConnectAnswer = Result<(KeyID, IDSend), crate::Error>;
|
|||
pub(crate) struct HandshakeClient {
|
||||
pub service_id: ServiceID,
|
||||
pub service_conn_id: IDRecv,
|
||||
pub connection: Connection,
|
||||
pub connection: Conn,
|
||||
pub timeout: Option<::tokio::task::JoinHandle<()>>,
|
||||
pub answer: oneshot::Sender<ConnectAnswer>,
|
||||
pub srv_key_id: KeyID,
|
||||
|
@ -79,7 +79,7 @@ impl HandshakeClientList {
|
|||
pub_key: PubKey,
|
||||
service_id: ServiceID,
|
||||
service_conn_id: IDRecv,
|
||||
connection: Connection,
|
||||
connection: Conn,
|
||||
answer: oneshot::Sender<ConnectAnswer>,
|
||||
srv_key_id: KeyID,
|
||||
) -> Result<(KeyID, &mut HandshakeClient), oneshot::Sender<ConnectAnswer>>
|
||||
|
@ -144,8 +144,8 @@ pub(crate) struct ClientConnectInfo {
|
|||
pub service_connection_id: IDRecv,
|
||||
/// Parsed handshake packet
|
||||
pub handshake: Handshake,
|
||||
/// Connection
|
||||
pub connection: Connection,
|
||||
/// Conn
|
||||
pub connection: Conn,
|
||||
/// where to wake up the waiting client
|
||||
pub answer: oneshot::Sender<ConnectAnswer>,
|
||||
/// server public key id that we used on the handshake
|
||||
|
@ -233,7 +233,7 @@ impl HandshakeTracker {
|
|||
pub_key: PubKey,
|
||||
service_id: ServiceID,
|
||||
service_conn_id: IDRecv,
|
||||
connection: Connection,
|
||||
connection: Conn,
|
||||
answer: oneshot::Sender<ConnectAnswer>,
|
||||
srv_key_id: KeyID,
|
||||
) -> Result<(KeyID, &mut HandshakeClient), oneshot::Sender<ConnectAnswer>>
|
||||
|
|
|
@ -3,13 +3,11 @@
|
|||
pub mod handshake;
|
||||
pub mod packet;
|
||||
pub mod socket;
|
||||
pub mod stream;
|
||||
|
||||
use ::std::{rc::Rc, vec::Vec};
|
||||
|
||||
pub use crate::connection::{
|
||||
handshake::Handshake,
|
||||
packet::{ConnectionID as ID, Packet, PacketData},
|
||||
};
|
||||
pub use crate::connection::{handshake::Handshake, packet::Packet};
|
||||
|
||||
use crate::{
|
||||
dnssec,
|
||||
|
@ -21,12 +19,93 @@ use crate::{
|
|||
},
|
||||
inner::ThreadTracker,
|
||||
};
|
||||
use ::std::rc;
|
||||
|
||||
/// Fenrir Connection ID
|
||||
///
|
||||
/// 0 is special as it represents the handshake
|
||||
/// Connection IDs are to be considered u64 little endian
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum ID {
|
||||
/// Connection id 0 represent the handshake
|
||||
Handshake,
|
||||
/// Non-zero id can represent any connection
|
||||
ID(::core::num::NonZeroU64),
|
||||
}
|
||||
|
||||
impl ID {
|
||||
/// Set the conenction id to handshake
|
||||
pub fn new_handshake() -> Self {
|
||||
Self::Handshake
|
||||
}
|
||||
/// New id from u64. PLZ NON ZERO
|
||||
pub(crate) fn new_u64(raw: u64) -> Self {
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
ID::ID(::core::num::NonZeroU64::new_unchecked(raw))
|
||||
}
|
||||
}
|
||||
pub(crate) fn as_u64(&self) -> u64 {
|
||||
match self {
|
||||
ID::Handshake => 0,
|
||||
ID::ID(id) => id.get(),
|
||||
}
|
||||
}
|
||||
/// New random service ID
|
||||
pub fn new_rand(rand: &Random) -> Self {
|
||||
let mut raw = [0; 8];
|
||||
let mut num = 0;
|
||||
while num == 0 {
|
||||
rand.fill(&mut raw);
|
||||
num = u64::from_le_bytes(raw);
|
||||
}
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
ID::ID(::core::num::NonZeroU64::new_unchecked(num))
|
||||
}
|
||||
}
|
||||
/// Quick check to know if this is an handshake
|
||||
pub fn is_handshake(&self) -> bool {
|
||||
*self == ID::Handshake
|
||||
}
|
||||
/// length if the connection ID in bytes
|
||||
pub const fn len() -> usize {
|
||||
8
|
||||
}
|
||||
/// write the ID to a buffer
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
match self {
|
||||
ID::Handshake => out[..8].copy_from_slice(&[0; 8]),
|
||||
ID::ID(id) => out[..8].copy_from_slice(&id.get().to_le_bytes()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for ID {
|
||||
fn from(raw: u64) -> Self {
|
||||
if raw == 0 {
|
||||
ID::Handshake
|
||||
} else {
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
ID::ID(::core::num::NonZeroU64::new_unchecked(raw))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 8]> for ID {
|
||||
fn from(raw: [u8; 8]) -> Self {
|
||||
let raw_u64 = u64::from_le_bytes(raw);
|
||||
raw_u64.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// strong typedef for receiving connection id
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct IDRecv(pub ID);
|
||||
/// strong typedef for sending connection id
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct IDSend(pub ID);
|
||||
|
||||
/// Version of the fenrir protocol in use
|
||||
|
@ -47,12 +126,16 @@ impl ProtocolVersion {
|
|||
}
|
||||
}
|
||||
|
||||
/// The connection, as seen from a user of libFenrir
|
||||
#[derive(Debug)]
|
||||
pub struct Connection(rc::Weak<Conn>);
|
||||
|
||||
/// A single connection and its data
|
||||
#[derive(Debug)]
|
||||
pub struct Connection {
|
||||
/// Receiving Connection ID
|
||||
pub(crate) struct Conn {
|
||||
/// Receiving Conn ID
|
||||
pub id_recv: IDRecv,
|
||||
/// Sending Connection ID
|
||||
/// Sending Conn ID
|
||||
pub id_send: IDSend,
|
||||
/// The main hkdf used for all secrets in this connection
|
||||
pub hkdf: Hkdf,
|
||||
|
@ -62,9 +145,12 @@ pub struct Connection {
|
|||
pub cipher_send: CipherSend,
|
||||
}
|
||||
|
||||
/// Role: used to set the correct secrets
|
||||
/// * Server: Connection is Incoming
|
||||
/// * Client: Connection is Outgoing
|
||||
/// Role: track the connection direction
|
||||
///
|
||||
/// The Role is used to select the correct secrets, and track the direction
|
||||
/// of the connection
|
||||
/// * Server: Conn is Incoming
|
||||
/// * Client: Conn is Outgoing
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum Role {
|
||||
|
@ -74,7 +160,7 @@ pub enum Role {
|
|||
Client,
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
impl Conn {
|
||||
pub(crate) fn new(
|
||||
hkdf: Hkdf,
|
||||
cipher: CipherKind,
|
||||
|
@ -102,11 +188,9 @@ impl Connection {
|
|||
}
|
||||
}
|
||||
|
||||
// PERF: Arc<RwLock<ConnList>> loks a bit too much, need to find
|
||||
// faster ways to do this
|
||||
pub(crate) struct ConnList {
|
||||
thread_id: ThreadTracker,
|
||||
connections: Vec<Option<Rc<Connection>>>,
|
||||
connections: Vec<Option<Rc<Conn>>>,
|
||||
/// Bitmap to track which connection ids are used or free
|
||||
ids_used: Vec<::bitmaps::Bitmap<1024>>,
|
||||
}
|
||||
|
@ -177,7 +261,7 @@ impl ConnList {
|
|||
new_id
|
||||
}
|
||||
/// 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<Conn>) -> Result<(), ()> {
|
||||
let conn_id = match conn.id_recv {
|
||||
IDRecv(ID::Handshake) => {
|
||||
return Err(());
|
||||
|
|
|
@ -1,107 +1,26 @@
|
|||
//
|
||||
//! Raw packet handling, encryption, decryption, parsing
|
||||
|
||||
use crate::enc::{
|
||||
sym::{HeadLen, TagLen},
|
||||
Random,
|
||||
use crate::{
|
||||
connection,
|
||||
enc::sym::{HeadLen, TagLen},
|
||||
};
|
||||
|
||||
/// Fenrir Connection id
|
||||
/// 0 is special as it represents the handshake
|
||||
/// Connection IDs are to be considered u64 little endian
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum ConnectionID {
|
||||
/// Connection id 0 represent the handshake
|
||||
Handshake,
|
||||
/// Non-zero id can represent any connection
|
||||
ID(::core::num::NonZeroU64),
|
||||
}
|
||||
|
||||
impl ConnectionID {
|
||||
/// Set the conenction id to handshake
|
||||
pub fn new_handshake() -> Self {
|
||||
Self::Handshake
|
||||
}
|
||||
/// New id from u64. PLZ NON ZERO
|
||||
pub(crate) fn new_u64(raw: u64) -> Self {
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
ConnectionID::ID(::core::num::NonZeroU64::new_unchecked(raw))
|
||||
}
|
||||
}
|
||||
pub(crate) fn as_u64(&self) -> u64 {
|
||||
match self {
|
||||
ConnectionID::Handshake => 0,
|
||||
ConnectionID::ID(id) => id.get(),
|
||||
}
|
||||
}
|
||||
/// New random service ID
|
||||
pub fn new_rand(rand: &Random) -> Self {
|
||||
let mut raw = [0; 8];
|
||||
let mut num = 0;
|
||||
while num == 0 {
|
||||
rand.fill(&mut raw);
|
||||
num = u64::from_le_bytes(raw);
|
||||
}
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
ConnectionID::ID(::core::num::NonZeroU64::new_unchecked(num))
|
||||
}
|
||||
}
|
||||
/// Quick check to know if this is an handshake
|
||||
pub fn is_handshake(&self) -> bool {
|
||||
*self == ConnectionID::Handshake
|
||||
}
|
||||
/// length if the connection ID in bytes
|
||||
pub const fn len() -> usize {
|
||||
8
|
||||
}
|
||||
/// write the ID to a buffer
|
||||
pub fn serialize(&self, out: &mut [u8]) {
|
||||
match self {
|
||||
ConnectionID::Handshake => out[..8].copy_from_slice(&[0; 8]),
|
||||
ConnectionID::ID(id) => {
|
||||
out[..8].copy_from_slice(&id.get().to_le_bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for ConnectionID {
|
||||
fn from(raw: u64) -> Self {
|
||||
if raw == 0 {
|
||||
ConnectionID::Handshake
|
||||
} else {
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
ConnectionID::ID(::core::num::NonZeroU64::new_unchecked(raw))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 8]> for ConnectionID {
|
||||
fn from(raw: [u8; 8]) -> Self {
|
||||
let raw_u64 = u64::from_le_bytes(raw);
|
||||
raw_u64.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Enumerate the possible data in a fenrir packet
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PacketData {
|
||||
pub enum Data {
|
||||
/// A parsed handshake packet
|
||||
Handshake(super::Handshake),
|
||||
/// Raw packet. we only have the connection ID and packet length
|
||||
Raw(usize),
|
||||
}
|
||||
|
||||
impl PacketData {
|
||||
impl Data {
|
||||
/// total length of the data in bytes
|
||||
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
|
||||
match self {
|
||||
PacketData::Handshake(h) => h.len(head_len, tag_len),
|
||||
PacketData::Raw(len) => *len,
|
||||
Data::Handshake(h) => h.len(head_len, tag_len),
|
||||
Data::Raw(len) => *len,
|
||||
}
|
||||
}
|
||||
/// serialize data into bytes
|
||||
|
@ -114,12 +33,12 @@ impl PacketData {
|
|||
) {
|
||||
assert!(
|
||||
self.len(head_len, tag_len) == out.len(),
|
||||
"PacketData: wrong buffer length"
|
||||
"Data: wrong buffer length"
|
||||
);
|
||||
match self {
|
||||
PacketData::Handshake(h) => h.serialize(head_len, tag_len, out),
|
||||
PacketData::Raw(_) => {
|
||||
::tracing::error!("Tried to serialize a raw PacketData!");
|
||||
Data::Handshake(h) => h.serialize(head_len, tag_len, out),
|
||||
Data::Raw(_) => {
|
||||
::tracing::error!("Tried to serialize a raw Data!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,9 +50,9 @@ const MIN_PACKET_BYTES: usize = 16;
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Packet {
|
||||
/// Id of the Fenrir connection.
|
||||
pub id: ConnectionID,
|
||||
pub id: connection::ID,
|
||||
/// actual data inside the packet
|
||||
pub data: PacketData,
|
||||
pub data: Data,
|
||||
}
|
||||
|
||||
impl Packet {
|
||||
|
@ -146,12 +65,12 @@ impl Packet {
|
|||
let raw_id: [u8; 8] = (raw[..8]).try_into().expect("unreachable");
|
||||
Ok(Packet {
|
||||
id: raw_id.into(),
|
||||
data: PacketData::Raw(raw.len()),
|
||||
data: Data::Raw(raw.len()),
|
||||
})
|
||||
}
|
||||
/// get the total length of the packet
|
||||
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
|
||||
ConnectionID::len() + self.data.len(head_len, tag_len)
|
||||
connection::ID::len() + self.data.len(head_len, tag_len)
|
||||
}
|
||||
/// serialize packet into buffer
|
||||
/// NOTE: assumes that there is exactly asa much buffer as needed
|
||||
|
@ -162,11 +81,14 @@ impl Packet {
|
|||
out: &mut [u8],
|
||||
) {
|
||||
assert!(
|
||||
out.len() > ConnectionID::len(),
|
||||
out.len() > connection::ID::len(),
|
||||
"Packet: not enough buffer to serialize"
|
||||
);
|
||||
self.id.serialize(&mut out[0..ConnectionID::len()]);
|
||||
self.data
|
||||
.serialize(head_len, tag_len, &mut out[ConnectionID::len()..]);
|
||||
self.id.serialize(&mut out[0..connection::ID::len()]);
|
||||
self.data.serialize(
|
||||
head_len,
|
||||
tag_len,
|
||||
&mut out[connection::ID::len()..],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
//! Errors while parsing streams
|
||||
|
||||
|
||||
/// Crypto errors
|
||||
#[derive(::thiserror::Error, Debug, Copy, Clone)]
|
||||
pub enum Error {
|
||||
/// Error while parsing key material
|
||||
#[error("Not enough data for stream chunk: {0}")]
|
||||
NotEnoughData(usize),
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
//! Here we implement the multiplexing stream feature of Fenrir
|
||||
//!
|
||||
//! For now we will only have the TCP-like, reliable, in-order delivery
|
||||
|
||||
mod errors;
|
||||
mod rob;
|
||||
pub use errors::Error;
|
||||
|
||||
use crate::{connection::stream::rob::ReliableOrderedBytestream, enc::Random};
|
||||
|
||||
/// Kind of stream. any combination of:
|
||||
/// reliable/unreliable ordered/unordered, bytestream/datagram
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum Kind {
|
||||
/// ROB: Reliable, Ordered, Bytestream
|
||||
/// AKA: TCP-like
|
||||
ROB = 0,
|
||||
}
|
||||
|
||||
/// Id of the stream
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ID(pub u16);
|
||||
|
||||
impl ID {
|
||||
/// Length of the serialized field
|
||||
pub const fn len() -> usize {
|
||||
2
|
||||
}
|
||||
}
|
||||
|
||||
/// length of the chunk
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ChunkLen(pub u16);
|
||||
|
||||
impl ChunkLen {
|
||||
/// Length of the serialized field
|
||||
pub const fn len() -> usize {
|
||||
2
|
||||
}
|
||||
}
|
||||
|
||||
/// Sequence number to rebuild the stream correctly
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Sequence(pub ::core::num::Wrapping<u32>);
|
||||
|
||||
impl Sequence {
|
||||
const SEQ_NOFLAG: u32 = 0x3FFFFFFF;
|
||||
/// return a new sequence number, starting at random
|
||||
pub fn new(rand: &Random) -> Self {
|
||||
let seq: u32 = 0;
|
||||
rand.fill(&mut seq.to_le_bytes());
|
||||
Self(::core::num::Wrapping(seq & Self::SEQ_NOFLAG))
|
||||
}
|
||||
/// Length of the serialized field
|
||||
pub const fn len() -> usize {
|
||||
4
|
||||
}
|
||||
}
|
||||
|
||||
/// Chunk of data representing a stream
|
||||
/// Every chunk is as follows:
|
||||
/// | id (2 bytes) | length (2 bytes) |
|
||||
/// | flag_start (1 BIT) | flag_end (1 BIT) | sequence (30 bits) |
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Chunk<'a> {
|
||||
/// Id of the stream this chunk is part of
|
||||
pub id: ID,
|
||||
/// Is this the beginning of a message?
|
||||
pub flag_start: bool,
|
||||
/// Is this the end of a message?
|
||||
pub flag_end: bool,
|
||||
/// Sequence number to reconstruct the Stream
|
||||
pub sequence: Sequence,
|
||||
data: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> Chunk<'a> {
|
||||
const FLAGS_EXCLUDED_BITMASK: u8 = 0x3F;
|
||||
const FLAG_START_BITMASK: u8 = 0x80;
|
||||
const FLAG_END_BITMASK: u8 = 0x40;
|
||||
/// Returns the total length of the chunk, including headers
|
||||
pub fn len(&self) -> usize {
|
||||
ID::len() + ChunkLen::len() + Sequence::len() + self.data.len()
|
||||
}
|
||||
/// deserialize a chunk of a stream
|
||||
pub fn deserialize(raw: &'a [u8]) -> Result<Self, Error> {
|
||||
if raw.len() <= ID::len() + ChunkLen::len() + Sequence::len() {
|
||||
return Err(Error::NotEnoughData(0));
|
||||
}
|
||||
|
||||
let id = ID(u16::from_le_bytes(raw[0..ID::len()].try_into().unwrap()));
|
||||
|
||||
let mut bytes_next = ID::len() + ChunkLen::len();
|
||||
let length = ChunkLen(u16::from_le_bytes(
|
||||
raw[ID::len()..bytes_next].try_into().unwrap(),
|
||||
));
|
||||
if ID::len() + ChunkLen::len() + Sequence::len() + length.0 as usize
|
||||
> raw.len()
|
||||
{
|
||||
return Err(Error::NotEnoughData(4));
|
||||
}
|
||||
|
||||
let flag_start = (raw[bytes_next] & Self::FLAG_START_BITMASK) != 0;
|
||||
let flag_end = (raw[bytes_next] & Self::FLAG_END_BITMASK) != 0;
|
||||
|
||||
let bytes = bytes_next + 1;
|
||||
bytes_next = bytes + Sequence::len();
|
||||
let mut sequence_bytes: [u8; Sequence::len()] =
|
||||
raw[bytes..bytes_next].try_into().unwrap();
|
||||
sequence_bytes[0] = sequence_bytes[0] & Self::FLAGS_EXCLUDED_BITMASK;
|
||||
let sequence =
|
||||
Sequence(::core::num::Wrapping(u32::from_le_bytes(sequence_bytes)));
|
||||
|
||||
Ok(Self {
|
||||
id,
|
||||
flag_start,
|
||||
flag_end,
|
||||
sequence,
|
||||
data: &raw[bytes_next..(bytes_next + length.0 as usize)],
|
||||
})
|
||||
}
|
||||
/// serialize a chunk of a stream
|
||||
pub fn serialize(&self, raw_out: &mut [u8]) {
|
||||
raw_out[0..ID::len()].copy_from_slice(&self.id.0.to_le_bytes());
|
||||
let mut bytes_next = ID::len() + ChunkLen::len();
|
||||
raw_out[ID::len()..bytes_next]
|
||||
.copy_from_slice(&(self.data.len() as u16).to_le_bytes());
|
||||
let bytes = bytes_next;
|
||||
bytes_next = bytes_next + Sequence::len();
|
||||
raw_out[bytes..bytes_next]
|
||||
.copy_from_slice(&self.sequence.0 .0.to_le_bytes());
|
||||
let mut flag_byte = raw_out[bytes] & Self::FLAGS_EXCLUDED_BITMASK;
|
||||
if self.flag_start {
|
||||
flag_byte = flag_byte | Self::FLAG_START_BITMASK;
|
||||
}
|
||||
if self.flag_end {
|
||||
flag_byte = flag_byte | Self::FLAG_END_BITMASK;
|
||||
}
|
||||
raw_out[bytes] = flag_byte;
|
||||
let bytes = bytes_next;
|
||||
bytes_next = bytes_next + self.data.len();
|
||||
raw_out[bytes..bytes_next].copy_from_slice(&self.data);
|
||||
}
|
||||
}
|
||||
|
||||
/// Kind of stream. any combination of:
|
||||
/// reliable/unreliable ordered/unordered, bytestream/datagram
|
||||
/// differences from Kind:
|
||||
/// * not public
|
||||
/// * has actual data
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum Tracker {
|
||||
/// ROB: Reliable, Ordered, Bytestream
|
||||
/// AKA: TCP-like
|
||||
ROB(ReliableOrderedBytestream),
|
||||
}
|
||||
|
||||
impl Tracker {
|
||||
pub(crate) fn new(kind: Kind, rand: &Random) -> Self {
|
||||
match kind {
|
||||
Kind::ROB => Tracker::ROB(ReliableOrderedBytestream::new(rand)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Actual stream-tracking structure
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Stream {
|
||||
id: ID,
|
||||
data: Tracker,
|
||||
}
|
||||
|
||||
impl Stream {
|
||||
pub(crate) fn new(kind: Kind, rand: &Random) -> Self {
|
||||
let id: u16 = 0;
|
||||
rand.fill(&mut id.to_le_bytes());
|
||||
Self {
|
||||
id: ID(id),
|
||||
data: Tracker::new(kind, rand),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
//! Implementation of the Reliable, Ordered, Bytestream transmission model
|
||||
//! AKA: TCP-like
|
||||
|
||||
use crate::{
|
||||
connection::stream::{Chunk, Error, Sequence},
|
||||
enc::Random,
|
||||
};
|
||||
|
||||
/// Reliable, Ordered, Bytestream stream tracker
|
||||
/// AKA: TCP-like
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ReliableOrderedBytestream {
|
||||
window_start: Sequence,
|
||||
window_len: usize,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ReliableOrderedBytestream {
|
||||
pub(crate) fn new(rand: &Random) -> Self {
|
||||
Self {
|
||||
window_start: Sequence::new(rand),
|
||||
window_len: 1048576, // 1MB. should be enough for anybody. (lol)
|
||||
data: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub(crate) fn recv(&mut self, chunk: Chunk) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -10,8 +10,9 @@ use crate::{
|
|||
tracker::{HandshakeAction, HandshakeTracker},
|
||||
Handshake, HandshakeData,
|
||||
},
|
||||
packet::{self, Packet},
|
||||
socket::{UdpClient, UdpServer},
|
||||
ConnList, Connection, IDSend, Packet,
|
||||
Conn, ConnList, IDSend,
|
||||
},
|
||||
dnssec,
|
||||
enc::{
|
||||
|
@ -125,6 +126,7 @@ impl Worker {
|
|||
handshakes,
|
||||
})
|
||||
}
|
||||
|
||||
/// Continuously loop and process work as needed
|
||||
pub async fn work_loop(&mut self) {
|
||||
'mainloop: loop {
|
||||
|
@ -292,7 +294,7 @@ impl Worker {
|
|||
// are PubKey::Exchange
|
||||
unreachable!()
|
||||
}
|
||||
let mut conn = Connection::new(
|
||||
let mut conn = Conn::new(
|
||||
hkdf,
|
||||
cipher_selected,
|
||||
connection::Role::Client,
|
||||
|
@ -345,7 +347,8 @@ impl Worker {
|
|||
exchange_key: pub_key,
|
||||
data: dirsync::ReqInner::ClearText(req_data),
|
||||
};
|
||||
let encrypt_start = ID::len() + req.encrypted_offset();
|
||||
let encrypt_start =
|
||||
connection::ID::len() + req.encrypted_offset();
|
||||
let encrypt_end = encrypt_start
|
||||
+ req.encrypted_length(
|
||||
cipher_selected.nonce_len(),
|
||||
|
@ -354,10 +357,9 @@ impl Worker {
|
|||
let h_req = Handshake::new(HandshakeData::DirSync(
|
||||
DirSync::Req(req),
|
||||
));
|
||||
use connection::{PacketData, ID};
|
||||
let packet = Packet {
|
||||
id: ID::Handshake,
|
||||
data: PacketData::Handshake(h_req),
|
||||
id: connection::ID::Handshake,
|
||||
data: packet::Data::Handshake(h_req),
|
||||
};
|
||||
|
||||
let tot_len = packet.len(
|
||||
|
@ -510,12 +512,12 @@ impl Worker {
|
|||
// Client has correctly authenticated
|
||||
// TODO: contact the service, get the key and
|
||||
// connection ID
|
||||
let srv_conn_id = ID::new_rand(&self.rand);
|
||||
let srv_conn_id = connection::ID::new_rand(&self.rand);
|
||||
let srv_secret = Secret::new_rand(&self.rand);
|
||||
let head_len = req.cipher.nonce_len();
|
||||
let tag_len = req.cipher.tag_len();
|
||||
|
||||
let mut auth_conn = Connection::new(
|
||||
let mut auth_conn = Conn::new(
|
||||
authinfo.hkdf,
|
||||
req.cipher,
|
||||
connection::Role::Server,
|
||||
|
@ -541,16 +543,16 @@ impl Worker {
|
|||
client_key_id: req_data.client_key_id,
|
||||
data: RespInner::ClearText(resp_data),
|
||||
};
|
||||
let encrypt_from = ID::len() + resp.encrypted_offset();
|
||||
let encrypt_from =
|
||||
connection::ID::len() + resp.encrypted_offset();
|
||||
let encrypt_until =
|
||||
encrypt_from + resp.encrypted_length(head_len, tag_len);
|
||||
let resp_handshake = Handshake::new(
|
||||
HandshakeData::DirSync(DirSync::Resp(resp)),
|
||||
);
|
||||
use connection::{PacketData, ID};
|
||||
let packet = Packet {
|
||||
id: ID::new_handshake(),
|
||||
data: PacketData::Handshake(resp_handshake),
|
||||
id: connection::ID::new_handshake(),
|
||||
data: packet::Data::Handshake(resp_handshake),
|
||||
};
|
||||
let tot_len = packet.len(head_len, tag_len);
|
||||
let mut raw_out = Vec::<u8>::with_capacity(tot_len);
|
||||
|
@ -611,7 +613,7 @@ impl Worker {
|
|||
cci.service_id.as_bytes(),
|
||||
resp_data.service_key,
|
||||
);
|
||||
let mut service_connection = Connection::new(
|
||||
let mut service_connection = Conn::new(
|
||||
hkdf,
|
||||
cipher,
|
||||
connection::Role::Client,
|
||||
|
|
|
@ -39,6 +39,7 @@ use crate::{
|
|||
},
|
||||
};
|
||||
pub use config::Config;
|
||||
pub use connection::Connection;
|
||||
|
||||
/// Main fenrir library errors
|
||||
#[derive(::thiserror::Error, Debug)]
|
||||
|
@ -332,7 +333,7 @@ impl Fenrir {
|
|||
let data: Vec<u8> = buffer[..bytes].to_vec();
|
||||
|
||||
// we very likely have multiple threads, pinned to different cpus.
|
||||
// use the ConnectionID to send the same connection
|
||||
// use the connection::ID to send the same connection
|
||||
// to the same thread.
|
||||
// Handshakes have connection ID 0, so we use the sender's UDP port
|
||||
|
||||
|
@ -341,13 +342,12 @@ impl Fenrir {
|
|||
Err(_) => continue, // packet way too short, ignore.
|
||||
};
|
||||
let thread_idx: usize = {
|
||||
use connection::packet::ConnectionID;
|
||||
match packet.id {
|
||||
ConnectionID::Handshake => {
|
||||
connection::ID::Handshake => {
|
||||
let send_port = sock_sender.0.port() as u64;
|
||||
(send_port % queues_num) as usize
|
||||
}
|
||||
ConnectionID::ID(id) => (id.get() % queues_num) as usize,
|
||||
connection::ID::ID(id) => (id.get() % queues_num) as usize,
|
||||
}
|
||||
};
|
||||
let _ = work_queues[thread_idx]
|
||||
|
|
Loading…
Reference in New Issue