Stream stubs, start using namespaces as intended
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
parent
d6825980fd
commit
cd7be0ff69
24
flake.lock
24
flake.lock
|
@ -5,11 +5,11 @@
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1681202837,
|
"lastModified": 1685518550,
|
||||||
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -38,11 +38,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1684922889,
|
"lastModified": 1686921029,
|
||||||
"narHash": "sha256-l0WZAmln8959O7RdYUJ3gnAIM9OPKFLKHKGX4q+Blrk=",
|
"narHash": "sha256-J1bX9plPCFhTSh6E3TWn9XSxggBh/zDD4xigyaIQBy8=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "04aaf8511678a0d0f347fdf1e8072fe01e4a509e",
|
"rev": "c7ff1b9b95620ce8728c0d7bd501c458e6da9e04",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -54,11 +54,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs-unstable": {
|
"nixpkgs-unstable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1684844536,
|
"lastModified": 1686960236,
|
||||||
"narHash": "sha256-M7HhXYVqAuNb25r/d3FOO0z4GxPqDIZp5UjHFbBgw0Q=",
|
"narHash": "sha256-AYCC9rXNLpUWzD9hm+askOfpliLEC9kwAo7ITJc4HIw=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d30264c2691128adc261d7c9388033645f0e742b",
|
"rev": "04af42f3b31dba0ef742d254456dc4c14eedac86",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -98,11 +98,11 @@
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1684894917,
|
"lastModified": 1687055571,
|
||||||
"narHash": "sha256-kwKCfmliHIxKuIjnM95TRcQxM/4AAEIZ+4A9nDJ6cJs=",
|
"narHash": "sha256-UvLoO6u5n9TzY80BpM4DaacxvyJl7u9mm9CA72d309g=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "9ea38d547100edcf0da19aaebbdffa2810585495",
|
"rev": "2de557c780dcb127128ae987fca9d6c2b0d7dc0f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
connection::{
|
connection::{
|
||||||
self,
|
self,
|
||||||
handshake::{self, Error, Handshake},
|
handshake::{self, Error, Handshake},
|
||||||
Connection, IDRecv, IDSend,
|
Conn, IDRecv, IDSend,
|
||||||
},
|
},
|
||||||
enc::{
|
enc::{
|
||||||
self,
|
self,
|
||||||
|
@ -29,7 +29,7 @@ pub(crate) type ConnectAnswer = Result<(KeyID, IDSend), crate::Error>;
|
||||||
pub(crate) struct HandshakeClient {
|
pub(crate) struct HandshakeClient {
|
||||||
pub service_id: ServiceID,
|
pub service_id: ServiceID,
|
||||||
pub service_conn_id: IDRecv,
|
pub service_conn_id: IDRecv,
|
||||||
pub connection: Connection,
|
pub connection: Conn,
|
||||||
pub timeout: Option<::tokio::task::JoinHandle<()>>,
|
pub timeout: Option<::tokio::task::JoinHandle<()>>,
|
||||||
pub answer: oneshot::Sender<ConnectAnswer>,
|
pub answer: oneshot::Sender<ConnectAnswer>,
|
||||||
pub srv_key_id: KeyID,
|
pub srv_key_id: KeyID,
|
||||||
|
@ -79,7 +79,7 @@ impl HandshakeClientList {
|
||||||
pub_key: PubKey,
|
pub_key: PubKey,
|
||||||
service_id: ServiceID,
|
service_id: ServiceID,
|
||||||
service_conn_id: IDRecv,
|
service_conn_id: IDRecv,
|
||||||
connection: Connection,
|
connection: Conn,
|
||||||
answer: oneshot::Sender<ConnectAnswer>,
|
answer: oneshot::Sender<ConnectAnswer>,
|
||||||
srv_key_id: KeyID,
|
srv_key_id: KeyID,
|
||||||
) -> Result<(KeyID, &mut HandshakeClient), oneshot::Sender<ConnectAnswer>>
|
) -> Result<(KeyID, &mut HandshakeClient), oneshot::Sender<ConnectAnswer>>
|
||||||
|
@ -144,8 +144,8 @@ pub(crate) struct ClientConnectInfo {
|
||||||
pub service_connection_id: IDRecv,
|
pub service_connection_id: IDRecv,
|
||||||
/// Parsed handshake packet
|
/// Parsed handshake packet
|
||||||
pub handshake: Handshake,
|
pub handshake: Handshake,
|
||||||
/// Connection
|
/// Conn
|
||||||
pub connection: Connection,
|
pub connection: Conn,
|
||||||
/// where to wake up the waiting client
|
/// where to wake up the waiting client
|
||||||
pub answer: oneshot::Sender<ConnectAnswer>,
|
pub answer: oneshot::Sender<ConnectAnswer>,
|
||||||
/// server public key id that we used on the handshake
|
/// server public key id that we used on the handshake
|
||||||
|
@ -233,7 +233,7 @@ impl HandshakeTracker {
|
||||||
pub_key: PubKey,
|
pub_key: PubKey,
|
||||||
service_id: ServiceID,
|
service_id: ServiceID,
|
||||||
service_conn_id: IDRecv,
|
service_conn_id: IDRecv,
|
||||||
connection: Connection,
|
connection: Conn,
|
||||||
answer: oneshot::Sender<ConnectAnswer>,
|
answer: oneshot::Sender<ConnectAnswer>,
|
||||||
srv_key_id: KeyID,
|
srv_key_id: KeyID,
|
||||||
) -> Result<(KeyID, &mut HandshakeClient), oneshot::Sender<ConnectAnswer>>
|
) -> Result<(KeyID, &mut HandshakeClient), oneshot::Sender<ConnectAnswer>>
|
||||||
|
|
|
@ -3,13 +3,11 @@
|
||||||
pub mod handshake;
|
pub mod handshake;
|
||||||
pub mod packet;
|
pub mod packet;
|
||||||
pub mod socket;
|
pub mod socket;
|
||||||
|
pub mod stream;
|
||||||
|
|
||||||
use ::std::{rc::Rc, vec::Vec};
|
use ::std::{rc::Rc, vec::Vec};
|
||||||
|
|
||||||
pub use crate::connection::{
|
pub use crate::connection::{handshake::Handshake, packet::Packet};
|
||||||
handshake::Handshake,
|
|
||||||
packet::{ConnectionID as ID, Packet, PacketData},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dnssec,
|
dnssec,
|
||||||
|
@ -21,12 +19,93 @@ use crate::{
|
||||||
},
|
},
|
||||||
inner::ThreadTracker,
|
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
|
/// strong typedef for receiving connection id
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct IDRecv(pub ID);
|
pub struct IDRecv(pub ID);
|
||||||
/// strong typedef for sending connection 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);
|
pub struct IDSend(pub ID);
|
||||||
|
|
||||||
/// Version of the fenrir protocol in use
|
/// 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
|
/// A single connection and its data
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Connection {
|
pub(crate) struct Conn {
|
||||||
/// Receiving Connection ID
|
/// Receiving Conn ID
|
||||||
pub id_recv: IDRecv,
|
pub id_recv: IDRecv,
|
||||||
/// Sending Connection ID
|
/// Sending Conn ID
|
||||||
pub id_send: IDSend,
|
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: Hkdf,
|
pub hkdf: Hkdf,
|
||||||
|
@ -62,9 +145,12 @@ pub struct Connection {
|
||||||
pub cipher_send: CipherSend,
|
pub cipher_send: CipherSend,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Role: used to set the correct secrets
|
/// Role: track the connection direction
|
||||||
/// * Server: Connection is Incoming
|
///
|
||||||
/// * Client: Connection is Outgoing
|
/// 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)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Role {
|
pub enum Role {
|
||||||
|
@ -74,7 +160,7 @@ pub enum Role {
|
||||||
Client,
|
Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Connection {
|
impl Conn {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
hkdf: Hkdf,
|
hkdf: Hkdf,
|
||||||
cipher: CipherKind,
|
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 {
|
pub(crate) struct ConnList {
|
||||||
thread_id: ThreadTracker,
|
thread_id: ThreadTracker,
|
||||||
connections: Vec<Option<Rc<Connection>>>,
|
connections: Vec<Option<Rc<Conn>>>,
|
||||||
/// Bitmap to track which connection ids are used or free
|
/// Bitmap to track which connection ids are used or free
|
||||||
ids_used: Vec<::bitmaps::Bitmap<1024>>,
|
ids_used: Vec<::bitmaps::Bitmap<1024>>,
|
||||||
}
|
}
|
||||||
|
@ -177,7 +261,7 @@ impl ConnList {
|
||||||
new_id
|
new_id
|
||||||
}
|
}
|
||||||
/// 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<Conn>) -> Result<(), ()> {
|
||||||
let conn_id = match conn.id_recv {
|
let conn_id = match conn.id_recv {
|
||||||
IDRecv(ID::Handshake) => {
|
IDRecv(ID::Handshake) => {
|
||||||
return Err(());
|
return Err(());
|
||||||
|
|
|
@ -1,107 +1,26 @@
|
||||||
//
|
//
|
||||||
//! Raw packet handling, encryption, decryption, parsing
|
//! Raw packet handling, encryption, decryption, parsing
|
||||||
|
|
||||||
use crate::enc::{
|
use crate::{
|
||||||
sym::{HeadLen, TagLen},
|
connection,
|
||||||
Random,
|
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
|
/// Enumerate the possible data in a fenrir packet
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum PacketData {
|
pub enum Data {
|
||||||
/// A parsed handshake packet
|
/// A parsed handshake packet
|
||||||
Handshake(super::Handshake),
|
Handshake(super::Handshake),
|
||||||
/// Raw packet. we only have the connection ID and packet length
|
/// Raw packet. we only have the connection ID and packet length
|
||||||
Raw(usize),
|
Raw(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketData {
|
impl Data {
|
||||||
/// total length of the data in bytes
|
/// total length of the data in bytes
|
||||||
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
|
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
|
||||||
match self {
|
match self {
|
||||||
PacketData::Handshake(h) => h.len(head_len, tag_len),
|
Data::Handshake(h) => h.len(head_len, tag_len),
|
||||||
PacketData::Raw(len) => *len,
|
Data::Raw(len) => *len,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// serialize data into bytes
|
/// serialize data into bytes
|
||||||
|
@ -114,12 +33,12 @@ impl PacketData {
|
||||||
) {
|
) {
|
||||||
assert!(
|
assert!(
|
||||||
self.len(head_len, tag_len) == out.len(),
|
self.len(head_len, tag_len) == out.len(),
|
||||||
"PacketData: wrong buffer length"
|
"Data: wrong buffer length"
|
||||||
);
|
);
|
||||||
match self {
|
match self {
|
||||||
PacketData::Handshake(h) => h.serialize(head_len, tag_len, out),
|
Data::Handshake(h) => h.serialize(head_len, tag_len, out),
|
||||||
PacketData::Raw(_) => {
|
Data::Raw(_) => {
|
||||||
::tracing::error!("Tried to serialize a raw PacketData!");
|
::tracing::error!("Tried to serialize a raw Data!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,9 +50,9 @@ const MIN_PACKET_BYTES: usize = 16;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Packet {
|
pub struct Packet {
|
||||||
/// Id of the Fenrir connection.
|
/// Id of the Fenrir connection.
|
||||||
pub id: ConnectionID,
|
pub id: connection::ID,
|
||||||
/// actual data inside the packet
|
/// actual data inside the packet
|
||||||
pub data: PacketData,
|
pub data: Data,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Packet {
|
impl Packet {
|
||||||
|
@ -146,12 +65,12 @@ impl Packet {
|
||||||
let raw_id: [u8; 8] = (raw[..8]).try_into().expect("unreachable");
|
let raw_id: [u8; 8] = (raw[..8]).try_into().expect("unreachable");
|
||||||
Ok(Packet {
|
Ok(Packet {
|
||||||
id: raw_id.into(),
|
id: raw_id.into(),
|
||||||
data: PacketData::Raw(raw.len()),
|
data: Data::Raw(raw.len()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/// get the total length of the packet
|
/// get the total length of the packet
|
||||||
pub fn len(&self, head_len: HeadLen, tag_len: TagLen) -> usize {
|
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
|
/// serialize packet into buffer
|
||||||
/// NOTE: assumes that there is exactly asa much buffer as needed
|
/// NOTE: assumes that there is exactly asa much buffer as needed
|
||||||
|
@ -162,11 +81,14 @@ impl Packet {
|
||||||
out: &mut [u8],
|
out: &mut [u8],
|
||||||
) {
|
) {
|
||||||
assert!(
|
assert!(
|
||||||
out.len() > ConnectionID::len(),
|
out.len() > connection::ID::len(),
|
||||||
"Packet: not enough buffer to serialize"
|
"Packet: not enough buffer to serialize"
|
||||||
);
|
);
|
||||||
self.id.serialize(&mut out[0..ConnectionID::len()]);
|
self.id.serialize(&mut out[0..connection::ID::len()]);
|
||||||
self.data
|
self.data.serialize(
|
||||||
.serialize(head_len, tag_len, &mut out[ConnectionID::len()..]);
|
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},
|
tracker::{HandshakeAction, HandshakeTracker},
|
||||||
Handshake, HandshakeData,
|
Handshake, HandshakeData,
|
||||||
},
|
},
|
||||||
|
packet::{self, Packet},
|
||||||
socket::{UdpClient, UdpServer},
|
socket::{UdpClient, UdpServer},
|
||||||
ConnList, Connection, IDSend, Packet,
|
Conn, ConnList, IDSend,
|
||||||
},
|
},
|
||||||
dnssec,
|
dnssec,
|
||||||
enc::{
|
enc::{
|
||||||
|
@ -125,6 +126,7 @@ impl Worker {
|
||||||
handshakes,
|
handshakes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Continuously loop and process work as needed
|
/// Continuously loop and process work as needed
|
||||||
pub async fn work_loop(&mut self) {
|
pub async fn work_loop(&mut self) {
|
||||||
'mainloop: loop {
|
'mainloop: loop {
|
||||||
|
@ -292,7 +294,7 @@ impl Worker {
|
||||||
// are PubKey::Exchange
|
// are PubKey::Exchange
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
let mut conn = Connection::new(
|
let mut conn = Conn::new(
|
||||||
hkdf,
|
hkdf,
|
||||||
cipher_selected,
|
cipher_selected,
|
||||||
connection::Role::Client,
|
connection::Role::Client,
|
||||||
|
@ -345,7 +347,8 @@ impl Worker {
|
||||||
exchange_key: pub_key,
|
exchange_key: pub_key,
|
||||||
data: dirsync::ReqInner::ClearText(req_data),
|
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
|
let encrypt_end = encrypt_start
|
||||||
+ req.encrypted_length(
|
+ req.encrypted_length(
|
||||||
cipher_selected.nonce_len(),
|
cipher_selected.nonce_len(),
|
||||||
|
@ -354,10 +357,9 @@ impl Worker {
|
||||||
let h_req = Handshake::new(HandshakeData::DirSync(
|
let h_req = Handshake::new(HandshakeData::DirSync(
|
||||||
DirSync::Req(req),
|
DirSync::Req(req),
|
||||||
));
|
));
|
||||||
use connection::{PacketData, ID};
|
|
||||||
let packet = Packet {
|
let packet = Packet {
|
||||||
id: ID::Handshake,
|
id: connection::ID::Handshake,
|
||||||
data: PacketData::Handshake(h_req),
|
data: packet::Data::Handshake(h_req),
|
||||||
};
|
};
|
||||||
|
|
||||||
let tot_len = packet.len(
|
let tot_len = packet.len(
|
||||||
|
@ -510,12 +512,12 @@ impl Worker {
|
||||||
// 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 = ID::new_rand(&self.rand);
|
let srv_conn_id = connection::ID::new_rand(&self.rand);
|
||||||
let srv_secret = Secret::new_rand(&self.rand);
|
let srv_secret = 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 mut auth_conn = Connection::new(
|
let mut auth_conn = Conn::new(
|
||||||
authinfo.hkdf,
|
authinfo.hkdf,
|
||||||
req.cipher,
|
req.cipher,
|
||||||
connection::Role::Server,
|
connection::Role::Server,
|
||||||
|
@ -541,16 +543,16 @@ impl Worker {
|
||||||
client_key_id: req_data.client_key_id,
|
client_key_id: req_data.client_key_id,
|
||||||
data: RespInner::ClearText(resp_data),
|
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 =
|
let encrypt_until =
|
||||||
encrypt_from + resp.encrypted_length(head_len, tag_len);
|
encrypt_from + resp.encrypted_length(head_len, tag_len);
|
||||||
let resp_handshake = Handshake::new(
|
let resp_handshake = Handshake::new(
|
||||||
HandshakeData::DirSync(DirSync::Resp(resp)),
|
HandshakeData::DirSync(DirSync::Resp(resp)),
|
||||||
);
|
);
|
||||||
use connection::{PacketData, ID};
|
|
||||||
let packet = Packet {
|
let packet = Packet {
|
||||||
id: ID::new_handshake(),
|
id: connection::ID::new_handshake(),
|
||||||
data: PacketData::Handshake(resp_handshake),
|
data: packet::Data::Handshake(resp_handshake),
|
||||||
};
|
};
|
||||||
let tot_len = packet.len(head_len, tag_len);
|
let tot_len = packet.len(head_len, tag_len);
|
||||||
let mut raw_out = Vec::<u8>::with_capacity(tot_len);
|
let mut raw_out = Vec::<u8>::with_capacity(tot_len);
|
||||||
|
@ -611,7 +613,7 @@ impl Worker {
|
||||||
cci.service_id.as_bytes(),
|
cci.service_id.as_bytes(),
|
||||||
resp_data.service_key,
|
resp_data.service_key,
|
||||||
);
|
);
|
||||||
let mut service_connection = Connection::new(
|
let mut service_connection = Conn::new(
|
||||||
hkdf,
|
hkdf,
|
||||||
cipher,
|
cipher,
|
||||||
connection::Role::Client,
|
connection::Role::Client,
|
||||||
|
|
|
@ -39,6 +39,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
pub use config::Config;
|
pub use config::Config;
|
||||||
|
pub use connection::Connection;
|
||||||
|
|
||||||
/// Main fenrir library errors
|
/// Main fenrir library errors
|
||||||
#[derive(::thiserror::Error, Debug)]
|
#[derive(::thiserror::Error, Debug)]
|
||||||
|
@ -332,7 +333,7 @@ impl Fenrir {
|
||||||
let data: Vec<u8> = buffer[..bytes].to_vec();
|
let data: Vec<u8> = buffer[..bytes].to_vec();
|
||||||
|
|
||||||
// we very likely have multiple threads, pinned to different cpus.
|
// 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.
|
// to the same thread.
|
||||||
// Handshakes have connection ID 0, so we use the sender's UDP port
|
// 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.
|
Err(_) => continue, // packet way too short, ignore.
|
||||||
};
|
};
|
||||||
let thread_idx: usize = {
|
let thread_idx: usize = {
|
||||||
use connection::packet::ConnectionID;
|
|
||||||
match packet.id {
|
match packet.id {
|
||||||
ConnectionID::Handshake => {
|
connection::ID::Handshake => {
|
||||||
let send_port = sock_sender.0.port() as u64;
|
let send_port = sock_sender.0.port() as u64;
|
||||||
(send_port % queues_num) as usize
|
(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]
|
let _ = work_queues[thread_idx]
|
||||||
|
|
Loading…
Reference in New Issue