-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(initial): initial now-proto-pdu code from IronRDP (#2)
- Loading branch information
1 parent
f3e20be
commit b24add8
Showing
34 changed files
with
5,358 additions
and
11 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
//! Buffer types for NOW protocol. | ||
use alloc::vec::Vec; | ||
|
||
use ironrdp_core::{ | ||
cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, | ||
ReadCursor, WriteCursor, | ||
}; | ||
|
||
use crate::VarU32; | ||
|
||
/// String value up to 2^32 bytes long. | ||
/// | ||
/// NOW-PROTO: NOW_LRGBUF | ||
#[derive(Debug, Clone, PartialEq, Eq)] | ||
pub struct NowLrgBuf(Vec<u8>); | ||
|
||
impl NowLrgBuf { | ||
const NAME: &'static str = "NOW_LRGBUF"; | ||
const FIXED_PART_SIZE: usize = 4; | ||
|
||
/// Create a new `NowLrgBuf` instance. Returns an error if the provided value is too large. | ||
pub fn new(value: impl Into<Vec<u8>>) -> DecodeResult<Self> { | ||
let value: Vec<u8> = value.into(); | ||
|
||
if value.len() > VarU32::MAX as usize { | ||
return Err(invalid_field_err!("data", "data is too large for NOW_LRGBUF")); | ||
} | ||
|
||
Self::ensure_message_size(value.len())?; | ||
|
||
Ok(NowLrgBuf(value)) | ||
} | ||
|
||
/// Get the buffer value. | ||
pub fn value(&self) -> &[u8] { | ||
self.0.as_slice() | ||
} | ||
|
||
fn ensure_message_size(buffer_size: usize) -> DecodeResult<()> { | ||
if buffer_size > usize::try_from(VarU32::MAX).expect("BUG: too small usize") { | ||
return Err(invalid_field_err!("data", "data is too large for NOW_LRGBUF")); | ||
} | ||
|
||
if buffer_size > usize::MAX - Self::FIXED_PART_SIZE { | ||
return Err(invalid_field_err!( | ||
"data", | ||
"data size is too large to fit in 32-bit usize" | ||
)); | ||
} | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
impl Encode for NowLrgBuf { | ||
fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { | ||
let encoded_size = self.size(); | ||
ensure_size!(in: dst, size: encoded_size); | ||
|
||
let len: u32 = self.0.len().try_into().expect("BUG: validated in constructor"); | ||
|
||
dst.write_u32(len); | ||
dst.write_slice(self.0.as_slice()); | ||
|
||
Ok(()) | ||
} | ||
|
||
fn name(&self) -> &'static str { | ||
Self::NAME | ||
} | ||
|
||
fn size(&self) -> usize { | ||
// <u32 size> + <data bytes> | ||
Self::FIXED_PART_SIZE | ||
.checked_add(self.0.len()) | ||
.expect("BUG: size overflow") | ||
} | ||
} | ||
|
||
impl Decode<'_> for NowLrgBuf { | ||
fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> { | ||
ensure_fixed_part_size!(in: src); | ||
|
||
let len: usize = cast_length!("len", src.read_u32())?; | ||
|
||
Self::ensure_message_size(len)?; | ||
|
||
ensure_size!(in: src, size: len); | ||
let bytes = src.read_slice(len); | ||
|
||
Ok(NowLrgBuf(bytes.to_vec())) | ||
} | ||
} | ||
|
||
impl From<NowLrgBuf> for Vec<u8> { | ||
fn from(buf: NowLrgBuf) -> Self { | ||
buf.0 | ||
} | ||
} | ||
|
||
/// Buffer up to 2^31 bytes long (Length has compact variable length encoding). | ||
/// | ||
/// NOW-PROTO: NOW_VARBUF | ||
#[derive(Debug, Clone, PartialEq, Eq)] | ||
pub struct NowVarBuf(Vec<u8>); | ||
|
||
impl NowVarBuf { | ||
const NAME: &'static str = "NOW_VARBUF"; | ||
|
||
/// Create a new `NowVarBuf` instance. Returns an error if the provided value is too large. | ||
pub fn new(value: impl Into<Vec<u8>>) -> DecodeResult<Self> { | ||
let value = value.into(); | ||
|
||
let _: u32 = value | ||
.len() | ||
.try_into() | ||
.ok() | ||
.and_then(|val| if val <= VarU32::MAX { Some(val) } else { None }) | ||
.ok_or_else(|| invalid_field_err!("data", "too large buffer"))?; | ||
|
||
Ok(NowVarBuf(value)) | ||
} | ||
|
||
/// Get the buffer value. | ||
pub fn value(&self) -> &[u8] { | ||
self.0.as_slice() | ||
} | ||
} | ||
|
||
impl Encode for NowVarBuf { | ||
fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { | ||
let encoded_size = self.size(); | ||
ensure_size!(in: dst, size: encoded_size); | ||
|
||
let len: u32 = self.0.len().try_into().expect("BUG: validated in constructor"); | ||
|
||
VarU32::new(len)?.encode(dst)?; | ||
dst.write_slice(self.0.as_slice()); | ||
|
||
Ok(()) | ||
} | ||
|
||
fn name(&self) -> &'static str { | ||
Self::NAME | ||
} | ||
|
||
fn size(&self) -> usize { | ||
// <variable-length size> + <data bytes> | ||
// NOTE: Wrapping add will not overflow because the size is limited by VarU32::MAX | ||
VarU32::new(self.0.len().try_into().expect("buffer size always fits into u32")) | ||
.expect("buffer size is validated in constructor and should not overflow") | ||
.size() | ||
.wrapping_add(self.0.len()) | ||
} | ||
} | ||
|
||
impl Decode<'_> for NowVarBuf { | ||
fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> { | ||
let len_u32 = VarU32::decode(src)?.value(); | ||
let len: usize = cast_length!("len", len_u32)?; | ||
|
||
ensure_size!(in: src, size: len); | ||
let bytes = src.read_slice(len); | ||
|
||
Ok(NowVarBuf(bytes.to_vec())) | ||
} | ||
} | ||
|
||
impl From<NowVarBuf> for Vec<u8> { | ||
fn from(buf: NowVarBuf) -> Self { | ||
buf.0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
use ironrdp_core::{ensure_fixed_part_size, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor}; | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
pub struct NowMessageClass(pub u8); | ||
|
||
impl NowMessageClass { | ||
/// NOW-PROTO: NOW_SYSTEM_MSG_CLASS_ID | ||
pub const SYSTEM: Self = Self(0x11); | ||
|
||
/// NOW-PROTO: NOW_SESSION_MSG_CLASS_ID | ||
pub const SESSION: Self = Self(0x12); | ||
|
||
/// NOW-PROTO: NOW_EXEC_MSG_CLASS_ID | ||
pub const EXEC: Self = Self(0x13); | ||
} | ||
|
||
/// The NOW_HEADER structure is the header common to all NOW protocol messages. | ||
/// | ||
/// NOW-PROTO: NOW_HEADER | ||
#[derive(Debug, Clone, PartialEq, Eq)] | ||
pub struct NowHeader { | ||
pub size: u32, | ||
pub class: NowMessageClass, | ||
pub kind: u8, | ||
pub flags: u16, | ||
} | ||
|
||
impl NowHeader { | ||
const NAME: &'static str = "NOW_HEADER"; | ||
pub const FIXED_PART_SIZE: usize = 8; | ||
} | ||
|
||
impl Encode for NowHeader { | ||
fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { | ||
ensure_fixed_part_size!(in: dst); | ||
|
||
dst.write_u32(self.size); | ||
dst.write_u8(self.class.0); | ||
dst.write_u8(self.kind); | ||
dst.write_u16(self.flags); | ||
|
||
Ok(()) | ||
} | ||
|
||
fn name(&self) -> &'static str { | ||
Self::NAME | ||
} | ||
|
||
fn size(&self) -> usize { | ||
Self::FIXED_PART_SIZE | ||
} | ||
} | ||
|
||
impl Decode<'_> for NowHeader { | ||
fn decode(src: &mut ReadCursor<'_>) -> DecodeResult<Self> { | ||
ensure_fixed_part_size!(in: src); | ||
|
||
let size = src.read_u32(); | ||
let class = NowMessageClass(src.read_u8()); | ||
let kind = src.read_u8(); | ||
let flags = src.read_u16(); | ||
|
||
Ok(NowHeader { | ||
size, | ||
class, | ||
kind, | ||
flags, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
//! This module contains `NOW-PROTO` core types definitions. | ||
mod buffer; | ||
mod header; | ||
mod number; | ||
mod status; | ||
mod string; | ||
|
||
pub use buffer::{NowLrgBuf, NowVarBuf}; | ||
pub use header::{NowHeader, NowMessageClass}; | ||
pub use number::{VarI16, VarI32, VarI64, VarU16, VarU32, VarU64}; | ||
pub use status::{NowSeverity, NowStatus, NowStatusCode}; | ||
pub use string::{NowLrgStr, NowString128, NowString16, NowString256, NowString32, NowString64, NowVarStr}; |
Oops, something went wrong.