Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions srt-protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ name = "srt-protocol"
publish = false
repository = "https://github.com/russelltg/srt-rs"
version = "0.1.0"

[dependencies]
array-init = "2.0.0"
arraydeque = "0.4.5"
Expand All @@ -25,6 +26,11 @@ streaming-stats = "0.2.3"
take-until = "0.1.0"
thiserror = "1.0.30"

[dependencies.arbitrary]
version = "1"
optional = true
features = ["derive"]

[dependencies.aes]
features = ["ctr"]
version = "0.7.5"
Expand All @@ -37,6 +43,7 @@ version = "0.4.14"
default-features = false
version = "0.10.0"


[dev-dependencies]
assert_matches = "1.0.0"
proptest = "1.0.0"
Expand Down
4 changes: 4 additions & 0 deletions srt-protocol/fuzz/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

target
corpus
artifacts
45 changes: 45 additions & 0 deletions srt-protocol/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

[package]
name = "srt-protocol-fuzz"
version = "0.0.0"
authors = ["Automatically generated"]
publish = false
edition = "2018"

[package.metadata]
cargo-fuzz = true

[dependencies]
libfuzzer-sys = "0.4"

[dependencies.srt-protocol]
path = ".."
features = ["arbitrary"]

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[[bin]]
name = "fuzz_target_1"
path = "fuzz_targets/fuzz_target_1.rs"
test = false
doc = false

[[bin]]
name = "packet_ipv6"
path = "fuzz_targets/packet_ipv6.rs"
test = false
doc = false

[[bin]]
name = "packet_ipv4"
path = "fuzz_targets/packet_ipv4.rs"
test = false
doc = false

[[bin]]
name = "connect"
path = "fuzz_targets/connect.rs"
test = false
doc = false
33 changes: 33 additions & 0 deletions srt-protocol/fuzz/fuzz_targets/connect.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#![no_main]
use libfuzzer_sys::{
arbitrary::{Arbitrary, Unstructured},
fuzz_target,
};

use srt_protocol::{
packet::Packet, packet::SeqNumber, protocol::pending_connection::connect::Connect,
settings::ConnInitSettings,
};

use std::time::Instant;

fuzz_target!(|data: &[u8]| {
// fuzzed code goes here
let mut uns = Unstructured::new(data);
let mut connect = Connect::new(
([127, 0, 0, 1], 2221).into(),
[127, 0, 0, 1].into(),
ConnInitSettings::default(),
None,
SeqNumber::new_truncate(123),
);
if let Ok(packet) = Packet::arbitrary(&mut uns) {
connect.handle_packet(Ok((packet, ([127, 0, 0, 1], 2221).into())), Instant::now());
}
if let Ok(packet) = Packet::arbitrary(&mut uns) {
connect.handle_packet(Ok((packet, ([127, 0, 0, 1], 2221).into())), Instant::now());
}
if let Ok(packet) = Packet::arbitrary(&mut uns) {
connect.handle_packet(Ok((packet, ([127, 0, 0, 1], 2221).into())), Instant::now());
}
});
8 changes: 8 additions & 0 deletions srt-protocol/fuzz/fuzz_targets/packet_ipv4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use srt_protocol::packet::Packet;
use std::io::Cursor;

fuzz_target!(|data: &[u8]| {
let _ = Packet::parse(&mut Cursor::new(data), false);
});
9 changes: 9 additions & 0 deletions srt-protocol/fuzz/fuzz_targets/packet_ipv6.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#![no_main]
use libfuzzer_sys::fuzz_target;

use srt_protocol::packet::Packet;
use std::io::Cursor;

fuzz_target!(|data: &[u8]| {
let _ = Packet::parse(&mut Cursor::new(data), true);
});
1 change: 1 addition & 0 deletions srt-protocol/src/options/srt_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::{cmp::Ordering, fmt};
/// Serialied, it looks like:
/// major * 0x10000 + minor * 0x100 + patch
#[derive(PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct SrtVersion {
pub major: u8,
pub minor: u8,
Expand Down
2 changes: 2 additions & 0 deletions srt-protocol/src/options/units.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ impl Div<PacketSize> for ByteCount {
}

#[derive(Debug, Deref, Display, Into, Add, Sub, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[display(fmt = "{} bytes", "_0")]
pub struct PacketSize(pub u64);

Expand All @@ -34,6 +35,7 @@ impl From<PacketSize> for usize {
}

#[derive(Debug, Deref, Display, Into, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[display(fmt = "{} packets", "_0")]
pub struct PacketCount(pub u64);

Expand Down
42 changes: 40 additions & 2 deletions srt-protocol/src/packet/control/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ use loss_compression::{compress_loss_list, decompress_loss_list};
/// ```
/// (from <https://tools.ietf.org/html/draft-gg-udt-03#page-5>)
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct ControlPacket {
/// The timestamp, relative to the socket start time (wrapping every 2^32 microseconds)
pub timestamp: TimeStamp,
Expand All @@ -66,6 +67,7 @@ impl ControlPacket {
/// The different kind of control packets
#[derive(Clone, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum ControlTypes {
/// The control packet for initiating connections, type 0x0
/// Does not use Additional Info
Expand Down Expand Up @@ -123,6 +125,7 @@ bitflags! {
}

#[derive(Clone, PartialEq, Eq, Debug, Default)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct HsV5Info {
/// the crypto size in bytes, either 0 (no encryption), 16, 24, or 32 (stored /8)
/// source: https://github.com/Haivision/srt/blob/master/docs/stransmit.md#medium-srt
Expand All @@ -143,6 +146,7 @@ pub struct HsV5Info {
/// HS-version dependenent data
#[derive(Clone, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum HandshakeVsInfo {
V4(SocketType),
V5(HsV5Info),
Expand Down Expand Up @@ -181,6 +185,7 @@ pub struct HandshakeControlInfo {
}

#[derive(Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct AckStatistics {
/// Round trip time+variance
pub rtt: Rtt,
Expand All @@ -195,6 +200,7 @@ pub struct AckStatistics {
}

#[derive(Clone, PartialEq, Eq, Debug, Copy, Ord, PartialOrd)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct FullAckSeqNumber(u32);

/// Data included in a ACK packet. [spec](https://datatracker.ietf.org/doc/html/draft-sharabayko-mops-srt-00#section-3.2.3)
Expand All @@ -211,17 +217,20 @@ pub struct FullAckSeqNumber(u32);
/// SeqNumber is the packet sequence number that all packets have been received until (excluding)
///
#[derive(Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Acknowledgement {
Lite(SeqNumber),
Small(SeqNumber, AckStatistics),
Full(SeqNumber, AckStatistics, FullAckSeqNumber),
}

#[derive(Clone, Eq, PartialEq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct CompressedLossList(Vec<u32>);

/// The socket type for a handshake.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum SocketType {
/// A stream socket, 1 when serialized
Stream = 1,
Expand All @@ -243,7 +252,7 @@ pub enum SocketType {
/// The rendezvous HSv4 (legacy):
/// --> WAVEAHAND (effective only if peer is also connecting)
/// <-- CONCLUSION (empty) (consider yourself connected upon reception)
/// --> AGREEMENT (sent as a response for conclusion, requires no response)
/// --> AGREEMENT
///
/// The rendezvous HSv5 (using SRT extensions):
/// --> WAVEAHAND (with cookie)
Expand All @@ -252,6 +261,7 @@ pub enum SocketType {
/// --> CONCLUSION (with response extensions, if RESPONDER)
/// <-- AGREEMENT (sent exclusively by INITIATOR upon reception of CONCLUSIOn with response extensions)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum ShakeType {
/// First handshake exchange in client-server connection
Induction,
Expand All @@ -272,6 +282,7 @@ pub enum ShakeType {

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum CoreRejectReason {
System = 1001,
Peer = 1002,
Expand All @@ -293,6 +304,7 @@ pub enum CoreRejectReason {

#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum ServerRejectReason {
Fallback = 2000,
KeyNotSup = 2001,
Expand Down Expand Up @@ -320,6 +332,7 @@ pub enum ServerRejectReason {
/// Reject code
/// *must* be >= 1000
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum RejectReason {
/// Core reject codes, [1000, 2000)
Core(CoreRejectReason),
Expand All @@ -333,6 +346,26 @@ pub enum RejectReason {
User(i32),
}

#[cfg(feature = "arbitrary")]
impl<'a> arbitrary::Arbitrary<'a> for HandshakeControlInfo {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
Ok(HandshakeControlInfo {
init_seq_num: SeqNumber::arbitrary(u)?,
max_packet_size: PacketSize::arbitrary(u)?,
max_flow_size: PacketCount::arbitrary(u)?,
shake_type: ShakeType::arbitrary(u)?,
socket_id: SocketId::arbitrary(u)?,
syn_cookie: i32::arbitrary(u)?,
peer_addr: if bool::arbitrary(u)? {
Ipv4Addr::arbitrary(u)?.into()
} else {
Ipv6Addr::arbitrary(u)?.into()
},
info: HandshakeVsInfo::arbitrary(u)?,
})
}
}

impl HandshakeVsInfo {
/// Get the type (V4) or ext flags (V5)
/// the shake_type is required to decide to encode the magic code
Expand Down Expand Up @@ -633,7 +666,12 @@ impl ControlTypes {
SrtControlPacket::StreamId(stream_id) => {
sid = Some(stream_id)
}
_ => unimplemented!("Implement other kinds"),
_ => {
// TODO, implement more
return Err(
PacketParseError::BadSrtExtensionMessage,
);
}
}
}
}
Expand Down
Loading