mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
9638581d09
This will be catched by the respective protocols, e.g. tcp and cause a violation
569 lines
17 KiB
Rust
569 lines
17 KiB
Rust
use crate::types::{Bandwidth, Mid, Pid, Prio, Promises, Sid};
|
|
use bytes::{Buf, BufMut, Bytes, BytesMut};
|
|
|
|
// const FRAME_RESERVED_1: u8 = 0;
|
|
const FRAME_HANDSHAKE: u8 = 1;
|
|
const FRAME_INIT: u8 = 2;
|
|
const FRAME_SHUTDOWN: u8 = 3;
|
|
const FRAME_OPEN_STREAM: u8 = 4;
|
|
const FRAME_CLOSE_STREAM: u8 = 5;
|
|
const FRAME_DATA_HEADER: u8 = 6;
|
|
const FRAME_DATA: u8 = 7;
|
|
const FRAME_RAW: u8 = 8;
|
|
//const FRAME_RESERVED_2: u8 = 10;
|
|
//const FRAME_RESERVED_3: u8 = 13;
|
|
|
|
/// Used for Communication between Channel <----(TCP/UDP)----> Channel
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum InitFrame {
|
|
Handshake {
|
|
magic_number: [u8; 7],
|
|
version: [u32; 3],
|
|
},
|
|
Init {
|
|
pid: Pid,
|
|
secret: u128,
|
|
},
|
|
/// WARNING: sending RAW is only for debug purposes and will drop the
|
|
/// connection
|
|
Raw(Vec<u8>),
|
|
}
|
|
|
|
/// Used for OUT TCP Communication between Channel --(TCP)--> Channel
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum OTFrame {
|
|
Shutdown, /* Shutdown this channel gracefully, if all channels are shutdown (gracefully),
|
|
* Participant is deleted */
|
|
OpenStream {
|
|
sid: Sid,
|
|
prio: Prio,
|
|
promises: Promises,
|
|
guaranteed_bandwidth: Bandwidth,
|
|
},
|
|
CloseStream {
|
|
sid: Sid,
|
|
},
|
|
DataHeader {
|
|
mid: Mid,
|
|
sid: Sid,
|
|
length: u64,
|
|
},
|
|
Data {
|
|
mid: Mid,
|
|
data: Bytes,
|
|
},
|
|
}
|
|
|
|
/// Used for IN TCP Communication between Channel <--(TCP)-- Channel
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum ITFrame {
|
|
Shutdown, /* Shutdown this channel gracefully, if all channels are shutdown (gracefully),
|
|
* Participant is deleted */
|
|
OpenStream {
|
|
sid: Sid,
|
|
prio: Prio,
|
|
promises: Promises,
|
|
guaranteed_bandwidth: Bandwidth,
|
|
},
|
|
CloseStream {
|
|
sid: Sid,
|
|
},
|
|
DataHeader {
|
|
mid: Mid,
|
|
sid: Sid,
|
|
length: u64,
|
|
},
|
|
Data {
|
|
mid: Mid,
|
|
data: BytesMut,
|
|
},
|
|
}
|
|
|
|
impl InitFrame {
|
|
// Size WITHOUT the 1rst indicating byte
|
|
pub(crate) const HANDSHAKE_CNS: usize = 19;
|
|
pub(crate) const INIT_CNS: usize = 32;
|
|
/// const part of the RAW frame, actual size is variable
|
|
pub(crate) const RAW_CNS: usize = 2;
|
|
|
|
//provide an appropriate buffer size. > 1500
|
|
pub(crate) fn write_bytes(self, bytes: &mut BytesMut) {
|
|
match self {
|
|
InitFrame::Handshake {
|
|
magic_number,
|
|
version,
|
|
} => {
|
|
bytes.put_u8(FRAME_HANDSHAKE);
|
|
bytes.put_slice(&magic_number);
|
|
bytes.put_u32_le(version[0]);
|
|
bytes.put_u32_le(version[1]);
|
|
bytes.put_u32_le(version[2]);
|
|
},
|
|
InitFrame::Init { pid, secret } => {
|
|
bytes.put_u8(FRAME_INIT);
|
|
pid.to_bytes(bytes);
|
|
bytes.put_u128_le(secret);
|
|
},
|
|
InitFrame::Raw(data) => {
|
|
bytes.put_u8(FRAME_RAW);
|
|
bytes.put_u16_le(data.len() as u16);
|
|
bytes.put_slice(&data);
|
|
},
|
|
}
|
|
}
|
|
|
|
pub(crate) fn read_frame(bytes: &mut BytesMut) -> Option<Self> {
|
|
let frame_no = match bytes.get(0) {
|
|
Some(&f) => f,
|
|
None => return None,
|
|
};
|
|
let frame = match frame_no {
|
|
FRAME_HANDSHAKE => {
|
|
if bytes.len() < Self::HANDSHAKE_CNS + 1 {
|
|
return None;
|
|
}
|
|
bytes.advance(1);
|
|
let mut magic_number_bytes = bytes.copy_to_bytes(7);
|
|
let mut magic_number = [0u8; 7];
|
|
magic_number_bytes.copy_to_slice(&mut magic_number);
|
|
InitFrame::Handshake {
|
|
magic_number,
|
|
version: [bytes.get_u32_le(), bytes.get_u32_le(), bytes.get_u32_le()],
|
|
}
|
|
},
|
|
FRAME_INIT => {
|
|
if bytes.len() < Self::INIT_CNS + 1 {
|
|
return None;
|
|
}
|
|
bytes.advance(1);
|
|
InitFrame::Init {
|
|
pid: Pid::from_bytes(bytes),
|
|
secret: bytes.get_u128_le(),
|
|
}
|
|
},
|
|
FRAME_RAW => {
|
|
if bytes.len() < Self::RAW_CNS + 1 {
|
|
return None;
|
|
}
|
|
bytes.advance(1);
|
|
let length = bytes.get_u16_le() as usize;
|
|
// lower length is allowed
|
|
let max_length = length.min(bytes.len());
|
|
let mut data = vec![0; max_length];
|
|
data.copy_from_slice(&bytes[..max_length]);
|
|
InitFrame::Raw(data)
|
|
},
|
|
_ => InitFrame::Raw(bytes.to_vec()),
|
|
};
|
|
Some(frame)
|
|
}
|
|
}
|
|
|
|
pub(crate) const TCP_CLOSE_STREAM_CNS: usize = 8;
|
|
/// const part of the DATA frame, actual size is variable
|
|
pub(crate) const TCP_DATA_CNS: usize = 10;
|
|
pub(crate) const TCP_DATA_HEADER_CNS: usize = 24;
|
|
pub(crate) const TCP_OPEN_STREAM_CNS: usize = 18;
|
|
// Size WITHOUT the 1rst indicating byte
|
|
pub(crate) const TCP_SHUTDOWN_CNS: usize = 0;
|
|
|
|
impl OTFrame {
|
|
pub fn write_bytes(self, bytes: &mut BytesMut) {
|
|
match self {
|
|
Self::Shutdown => {
|
|
bytes.put_u8(FRAME_SHUTDOWN);
|
|
},
|
|
Self::OpenStream {
|
|
sid,
|
|
prio,
|
|
promises,
|
|
guaranteed_bandwidth,
|
|
} => {
|
|
bytes.put_u8(FRAME_OPEN_STREAM);
|
|
sid.to_bytes(bytes);
|
|
bytes.put_u8(prio);
|
|
bytes.put_u8(promises.to_le_bytes()[0]);
|
|
bytes.put_u64_le(guaranteed_bandwidth);
|
|
},
|
|
Self::CloseStream { sid } => {
|
|
bytes.put_u8(FRAME_CLOSE_STREAM);
|
|
sid.to_bytes(bytes);
|
|
},
|
|
Self::DataHeader { mid, sid, length } => {
|
|
bytes.put_u8(FRAME_DATA_HEADER);
|
|
bytes.put_u64_le(mid);
|
|
sid.to_bytes(bytes);
|
|
bytes.put_u64_le(length);
|
|
},
|
|
Self::Data { mid, data } => {
|
|
bytes.put_u8(FRAME_DATA);
|
|
bytes.put_u64_le(mid);
|
|
bytes.put_u16_le(data.len() as u16);
|
|
bytes.put_slice(&data);
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ITFrame {
|
|
/// Err => cannot recover
|
|
/// Ok(None) => waiting for more data
|
|
pub(crate) fn read_frame(bytes: &mut BytesMut) -> Result<Option<Self>, ()> {
|
|
let frame_no = match bytes.first() {
|
|
Some(&f) => f,
|
|
None => return Ok(None),
|
|
};
|
|
let size = match frame_no {
|
|
FRAME_SHUTDOWN => TCP_SHUTDOWN_CNS,
|
|
FRAME_OPEN_STREAM => TCP_OPEN_STREAM_CNS,
|
|
FRAME_CLOSE_STREAM => TCP_CLOSE_STREAM_CNS,
|
|
FRAME_DATA_HEADER => TCP_DATA_HEADER_CNS,
|
|
FRAME_DATA => {
|
|
if bytes.len() < 9 + 1 + 1 {
|
|
return Ok(None);
|
|
}
|
|
u16::from_le_bytes([bytes[8 + 1], bytes[9 + 1]]) as usize + TCP_DATA_CNS
|
|
},
|
|
_ => return Err(()),
|
|
};
|
|
|
|
if bytes.len() < size + 1 {
|
|
return Ok(None);
|
|
}
|
|
|
|
let frame = match frame_no {
|
|
FRAME_SHUTDOWN => {
|
|
let _ = bytes.split_to(size + 1);
|
|
Self::Shutdown
|
|
},
|
|
FRAME_OPEN_STREAM => {
|
|
let mut bytes = bytes.split_to(size + 1);
|
|
bytes.advance(1);
|
|
Self::OpenStream {
|
|
sid: Sid::from_bytes(&mut bytes),
|
|
prio: bytes.get_u8(),
|
|
promises: Promises::from_bits_truncate(bytes.get_u8()),
|
|
guaranteed_bandwidth: bytes.get_u64_le(),
|
|
}
|
|
},
|
|
FRAME_CLOSE_STREAM => {
|
|
let mut bytes = bytes.split_to(size + 1);
|
|
bytes.advance(1);
|
|
Self::CloseStream {
|
|
sid: Sid::from_bytes(&mut bytes),
|
|
}
|
|
},
|
|
FRAME_DATA_HEADER => {
|
|
let mut bytes = bytes.split_to(size + 1);
|
|
bytes.advance(1);
|
|
Self::DataHeader {
|
|
mid: bytes.get_u64_le(),
|
|
sid: Sid::from_bytes(&mut bytes),
|
|
length: bytes.get_u64_le(),
|
|
}
|
|
},
|
|
FRAME_DATA => {
|
|
bytes.advance(1);
|
|
let mid = bytes.get_u64_le();
|
|
let length = bytes.get_u16_le();
|
|
debug_assert_eq!(length as usize, size - TCP_DATA_CNS);
|
|
let data = bytes.split_to(length as usize);
|
|
Self::Data { mid, data }
|
|
},
|
|
_ => unreachable!("Frame::to_frame should be handled before!"),
|
|
};
|
|
Ok(Some(frame))
|
|
}
|
|
}
|
|
|
|
#[allow(unused_variables)]
|
|
impl PartialEq<ITFrame> for OTFrame {
|
|
fn eq(&self, other: &ITFrame) -> bool {
|
|
match self {
|
|
Self::Shutdown => matches!(other, ITFrame::Shutdown),
|
|
Self::OpenStream {
|
|
sid,
|
|
prio,
|
|
promises,
|
|
guaranteed_bandwidth,
|
|
} => matches!(other, ITFrame::OpenStream {
|
|
sid,
|
|
prio,
|
|
promises,
|
|
guaranteed_bandwidth,
|
|
}),
|
|
Self::CloseStream { sid } => matches!(other, ITFrame::CloseStream { sid }),
|
|
Self::DataHeader { mid, sid, length } => {
|
|
matches!(other, ITFrame::DataHeader { mid, sid, length })
|
|
},
|
|
Self::Data { mid, data } => matches!(other, ITFrame::Data { mid, data }),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::types::{VELOREN_MAGIC_NUMBER, VELOREN_NETWORK_VERSION};
|
|
|
|
fn get_initframes() -> Vec<InitFrame> {
|
|
vec![
|
|
InitFrame::Handshake {
|
|
magic_number: VELOREN_MAGIC_NUMBER,
|
|
version: VELOREN_NETWORK_VERSION,
|
|
},
|
|
InitFrame::Init {
|
|
pid: Pid::fake(0),
|
|
secret: 0u128,
|
|
},
|
|
InitFrame::Raw(vec![1, 2, 3]),
|
|
]
|
|
}
|
|
|
|
fn get_otframes() -> Vec<OTFrame> {
|
|
vec![
|
|
OTFrame::OpenStream {
|
|
sid: Sid::new(1337),
|
|
prio: 14,
|
|
promises: Promises::GUARANTEED_DELIVERY,
|
|
guaranteed_bandwidth: 1_000_000,
|
|
},
|
|
OTFrame::DataHeader {
|
|
sid: Sid::new(1337),
|
|
mid: 0,
|
|
length: 36,
|
|
},
|
|
OTFrame::Data {
|
|
mid: 0,
|
|
data: Bytes::from(&[77u8; 20][..]),
|
|
},
|
|
OTFrame::Data {
|
|
mid: 0,
|
|
data: Bytes::from(&[42u8; 16][..]),
|
|
},
|
|
OTFrame::CloseStream {
|
|
sid: Sid::new(1337),
|
|
},
|
|
OTFrame::Shutdown,
|
|
]
|
|
}
|
|
|
|
#[test]
|
|
fn initframe_individual() {
|
|
let dupl = |frame: InitFrame| {
|
|
let mut buffer = BytesMut::with_capacity(1500);
|
|
InitFrame::write_bytes(frame, &mut buffer);
|
|
InitFrame::read_frame(&mut buffer)
|
|
};
|
|
|
|
for frame in get_initframes() {
|
|
println!("initframe: {:?}", &frame);
|
|
assert_eq!(Some(frame.clone()), dupl(frame));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn initframe_multiple() {
|
|
let mut buffer = BytesMut::with_capacity(3000);
|
|
|
|
let mut frames = get_initframes();
|
|
// to string
|
|
for f in &frames {
|
|
InitFrame::write_bytes(f.clone(), &mut buffer);
|
|
}
|
|
|
|
// from string
|
|
let mut framesd = frames
|
|
.iter()
|
|
.map(|&_| InitFrame::read_frame(&mut buffer))
|
|
.collect::<Vec<_>>();
|
|
|
|
// compare
|
|
for (f, fd) in frames.drain(..).zip(framesd.drain(..)) {
|
|
println!("initframe: {:?}", &f);
|
|
assert_eq!(Some(f), fd);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn frame_individual() {
|
|
let dupl = |frame: OTFrame| {
|
|
let mut buffer = BytesMut::with_capacity(1500);
|
|
OTFrame::write_bytes(frame, &mut buffer);
|
|
ITFrame::read_frame(&mut buffer)
|
|
};
|
|
|
|
for frame in get_otframes() {
|
|
println!("frame: {:?}", &frame);
|
|
assert_eq!(frame.clone(), dupl(frame).expect("ERR").expect("NONE"));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn frame_multiple() {
|
|
let mut buffer = BytesMut::with_capacity(3000);
|
|
|
|
let mut frames = get_otframes();
|
|
// to string
|
|
for f in &frames {
|
|
OTFrame::write_bytes(f.clone(), &mut buffer);
|
|
}
|
|
|
|
// from string
|
|
let mut framesd = frames
|
|
.iter()
|
|
.map(|&_| ITFrame::read_frame(&mut buffer))
|
|
.collect::<Vec<_>>();
|
|
|
|
// compare
|
|
for (f, fd) in frames.drain(..).zip(framesd.drain(..)) {
|
|
println!("frame: {:?}", &f);
|
|
assert_eq!(f, fd.expect("ERR").expect("NONE"));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn frame_exact_size() {
|
|
const SIZE: usize = TCP_CLOSE_STREAM_CNS+1/*first byte*/;
|
|
let mut buffer = BytesMut::with_capacity(SIZE);
|
|
|
|
let frame1 = OTFrame::CloseStream { sid: Sid::new(2) };
|
|
OTFrame::write_bytes(frame1.clone(), &mut buffer);
|
|
assert_eq!(buffer.len(), SIZE);
|
|
let mut deque = buffer.iter().copied().collect();
|
|
let frame2 = ITFrame::read_frame(&mut deque);
|
|
assert_eq!(frame1, frame2.expect("ERR").expect("NONE"));
|
|
}
|
|
|
|
#[test]
|
|
fn initframe_too_short_buffer() {
|
|
let mut buffer = BytesMut::with_capacity(10);
|
|
|
|
let frame1 = InitFrame::Handshake {
|
|
magic_number: VELOREN_MAGIC_NUMBER,
|
|
version: VELOREN_NETWORK_VERSION,
|
|
};
|
|
InitFrame::write_bytes(frame1, &mut buffer);
|
|
}
|
|
|
|
#[test]
|
|
fn initframe_too_less_data() {
|
|
let mut buffer = BytesMut::with_capacity(20);
|
|
|
|
let frame1 = InitFrame::Handshake {
|
|
magic_number: VELOREN_MAGIC_NUMBER,
|
|
version: VELOREN_NETWORK_VERSION,
|
|
};
|
|
let _ = InitFrame::write_bytes(frame1, &mut buffer);
|
|
buffer.truncate(6); // simulate partial retrieve
|
|
let frame1d = InitFrame::read_frame(&mut buffer);
|
|
assert_eq!(frame1d, None);
|
|
}
|
|
|
|
#[test]
|
|
fn initframe_rubish() {
|
|
let mut buffer = BytesMut::from(&b"dtrgwcser"[..]);
|
|
assert_eq!(
|
|
InitFrame::read_frame(&mut buffer),
|
|
Some(InitFrame::Raw(b"dtrgwcser".to_vec()))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn initframe_attack_too_much_length() {
|
|
let mut buffer = BytesMut::with_capacity(50);
|
|
|
|
let frame1 = InitFrame::Raw(b"foobar".to_vec());
|
|
let _ = InitFrame::write_bytes(frame1.clone(), &mut buffer);
|
|
buffer[1] = 255;
|
|
let framed = InitFrame::read_frame(&mut buffer);
|
|
assert_eq!(framed, Some(frame1));
|
|
}
|
|
|
|
#[test]
|
|
fn initframe_attack_too_low_length() {
|
|
let mut buffer = BytesMut::with_capacity(50);
|
|
|
|
let frame1 = InitFrame::Raw(b"foobar".to_vec());
|
|
let _ = InitFrame::write_bytes(frame1, &mut buffer);
|
|
buffer[1] = 3;
|
|
let framed = InitFrame::read_frame(&mut buffer);
|
|
// we accept a different frame here, as it's RAW and debug only!
|
|
assert_eq!(framed, Some(InitFrame::Raw(b"foo".to_vec())));
|
|
}
|
|
|
|
#[test]
|
|
fn frame_too_short_buffer() {
|
|
let mut buffer = BytesMut::with_capacity(10);
|
|
|
|
let frame1 = OTFrame::OpenStream {
|
|
sid: Sid::new(88),
|
|
promises: Promises::ENCRYPTED,
|
|
prio: 88,
|
|
guaranteed_bandwidth: 1_000_000,
|
|
};
|
|
OTFrame::write_bytes(frame1, &mut buffer);
|
|
}
|
|
|
|
#[test]
|
|
fn frame_too_less_data() {
|
|
let mut buffer = BytesMut::with_capacity(20);
|
|
|
|
let frame1 = OTFrame::OpenStream {
|
|
sid: Sid::new(88),
|
|
promises: Promises::ENCRYPTED,
|
|
prio: 88,
|
|
guaranteed_bandwidth: 1_000_000,
|
|
};
|
|
OTFrame::write_bytes(frame1, &mut buffer);
|
|
buffer.truncate(6); // simulate partial retrieve
|
|
let frame1d = ITFrame::read_frame(&mut buffer);
|
|
assert_eq!(frame1d, Ok(None));
|
|
}
|
|
|
|
#[test]
|
|
fn frame_rubish() {
|
|
let mut buffer = BytesMut::from(&b"dtrgwcser"[..]);
|
|
assert_eq!(ITFrame::read_frame(&mut buffer), Err(()));
|
|
}
|
|
|
|
#[test]
|
|
fn frame_attack_too_much_length() {
|
|
let mut buffer = BytesMut::with_capacity(50);
|
|
|
|
let frame1 = OTFrame::Data {
|
|
mid: 7u64,
|
|
data: Bytes::from(&b"foobar"[..]),
|
|
};
|
|
|
|
OTFrame::write_bytes(frame1, &mut buffer);
|
|
buffer[9] = 255;
|
|
let framed = ITFrame::read_frame(&mut buffer);
|
|
assert_eq!(framed, Ok(None));
|
|
}
|
|
|
|
#[test]
|
|
fn frame_attack_too_low_length() {
|
|
let mut buffer = BytesMut::with_capacity(50);
|
|
|
|
let frame1 = OTFrame::Data {
|
|
mid: 7u64,
|
|
data: Bytes::from(&b"foobar"[..]),
|
|
};
|
|
|
|
OTFrame::write_bytes(frame1, &mut buffer);
|
|
buffer[9] = 3;
|
|
let framed = ITFrame::read_frame(&mut buffer);
|
|
assert_eq!(
|
|
framed,
|
|
Ok(Some(ITFrame::Data {
|
|
mid: 7u64,
|
|
data: BytesMut::from(&b"foo"[..]),
|
|
}))
|
|
);
|
|
//next = Invalid => Empty
|
|
let framed = ITFrame::read_frame(&mut buffer);
|
|
assert_eq!(framed, Err(()));
|
|
}
|
|
}
|