use rsiprtp::rtp::{RtpPacket, RtpParseError};
use rsiprtp::sdp::SessionDescription;
use rsiprtp::sip::SipMessage;
mod sip_security {
use super::*;
#[test]
fn test_extremely_long_header() {
let long_value = "A".repeat(100000);
let msg = format!(
"INVITE sip:bob@example.com SIP/2.0\r\n\
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\r\n\
Max-Forwards: 70\r\n\
To: Bob <sip:bob@biloxi.com>\r\n\
From: {}<sip:alice@atlanta.com>;tag=1928301774\r\n\
Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n\
CSeq: 314159 INVITE\r\n\
Content-Length: 0\r\n\
\r\n",
long_value
);
let result = SipMessage::parse(msg.as_bytes());
let _ = result;
}
#[test]
fn test_content_length_overflow() {
let msg = b"INVITE sip:bob@biloxi.com SIP/2.0\r\n\
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\r\n\
Max-Forwards: 70\r\n\
To: Bob <sip:bob@biloxi.com>\r\n\
From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\n\
Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n\
CSeq: 314159 INVITE\r\n\
Content-Length: 99999999999999999999999999999\r\n\
\r\n";
let result = SipMessage::parse(msg);
let _ = result;
}
#[test]
fn test_negative_content_length() {
let msg = b"INVITE sip:bob@biloxi.com SIP/2.0\r\n\
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\r\n\
Max-Forwards: 70\r\n\
To: Bob <sip:bob@biloxi.com>\r\n\
From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\n\
Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n\
CSeq: 314159 INVITE\r\n\
Content-Length: -100\r\n\
\r\n";
let result = SipMessage::parse(msg);
let _ = result;
}
#[test]
fn test_content_length_mismatch() {
let msg = b"INVITE sip:bob@biloxi.com SIP/2.0\r\n\
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\r\n\
Max-Forwards: 70\r\n\
To: Bob <sip:bob@biloxi.com>\r\n\
From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\n\
Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n\
CSeq: 314159 INVITE\r\n\
Content-Type: application/sdp\r\n\
Content-Length: 1000\r\n\
\r\n\
v=0\r\n";
let result = SipMessage::parse(msg);
let _ = result;
}
#[test]
fn test_null_byte_injection() {
let msg = b"INVITE sip:bob@biloxi.com SIP/2.0\r\n\
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\r\n\
Max-Forwards: 70\r\n\
To: Bob\x00Admin <sip:bob@biloxi.com>\r\n\
From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\n\
Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n\
CSeq: 314159 INVITE\r\n\
Content-Length: 0\r\n\
\r\n";
let result = SipMessage::parse(msg);
let _ = result;
}
#[test]
fn test_crlf_injection() {
let msg = b"INVITE sip:bob@biloxi.com SIP/2.0\r\n\
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\r\n\
Max-Forwards: 70\r\n\
To: Bob <sip:bob@biloxi.com>\r\n\
From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\nX-Injected: evil\r\n\
Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n\
CSeq: 314159 INVITE\r\n\
Content-Length: 0\r\n\
\r\n";
let result = SipMessage::parse(msg);
let _ = result;
}
#[test]
fn test_deeply_nested_via_headers() {
let mut msg = "INVITE sip:bob@biloxi.com SIP/2.0\r\n".to_string();
for i in 0..1000 {
msg.push_str(&format!(
"Via: SIP/2.0/UDP proxy{}.example.com;branch=z9hG4bK{}\r\n",
i, i
));
}
msg.push_str(
"Max-Forwards: 70\r\n\
To: Bob <sip:bob@biloxi.com>\r\n\
From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\n\
Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n\
CSeq: 314159 INVITE\r\n\
Content-Length: 0\r\n\
\r\n",
);
let result = SipMessage::parse(msg.as_bytes());
let _ = result;
}
#[test]
fn test_truncated_headers() {
let msg = b"INVITE sip:bob@biloxi.com SIP/2.0\r\n\
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\r\n\
Max-Forwards: 70\r\n\
To: Bob <sip:bob@bilo";
let result = SipMessage::parse(msg);
assert!(result.is_err() || result.is_ok());
}
#[test]
fn test_missing_body_separator() {
let msg = b"INVITE sip:bob@biloxi.com SIP/2.0\r\n\
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\r\n\
Max-Forwards: 70\r\n\
To: Bob <sip:bob@biloxi.com>\r\n\
From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\n\
Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n\
CSeq: 314159 INVITE\r\n\
Content-Length: 10\r\n";
let result = SipMessage::parse(msg);
let _ = result;
}
#[test]
fn test_invalid_utf8() {
let mut msg = b"INVITE sip:bob@biloxi.com SIP/2.0\r\n\
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\r\n\
Max-Forwards: 70\r\n\
To: "
.to_vec();
msg.extend_from_slice(&[0xFF, 0xFE, 0xFD]);
msg.extend_from_slice(
b" <sip:bob@biloxi.com>\r\n\
From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\n\
Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n\
CSeq: 314159 INVITE\r\n\
Content-Length: 0\r\n\
\r\n",
);
let result = SipMessage::parse(&msg);
let _ = result;
}
#[test]
fn test_multiple_content_length() {
let msg = b"INVITE sip:bob@biloxi.com SIP/2.0\r\n\
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds\r\n\
Max-Forwards: 70\r\n\
To: Bob <sip:bob@biloxi.com>\r\n\
From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\n\
Call-ID: a84b4c76e66710@pc33.atlanta.com\r\n\
CSeq: 314159 INVITE\r\n\
Content-Length: 10\r\n\
Content-Length: 20\r\n\
\r\n\
0123456789";
let result = SipMessage::parse(msg);
let _ = result;
}
}
mod sdp_security {
use super::*;
#[test]
fn test_extremely_long_sdp_line() {
let long_session_name = "A".repeat(100000);
let sdp = format!(
"v=0\r\n\
o=- 123 456 IN IP4 192.168.1.1\r\n\
s={}\r\n\
t=0 0\r\n",
long_session_name
);
let result = SessionDescription::parse(&sdp);
let _ = result;
}
#[test]
fn test_malformed_origin_fields() {
let sdp = "v=0\r\n\
o=user 123 456\r\n\
s=-\r\n\
t=0 0\r\n";
let result = SessionDescription::parse(sdp);
assert!(result.is_err());
}
#[test]
fn test_sdp_session_name_injection() {
let sdp = "v=0\r\n\
o=- 123 456 IN IP4 192.168.1.1\r\n\
s=Normal\r\nv=1\r\nm=evil 666 RTP/AVP 0\r\n\
t=0 0\r\n";
let result = SessionDescription::parse(sdp);
if let Ok(parsed) = result {
assert_eq!(parsed.version, 0);
}
}
#[test]
fn test_invalid_ip_address() {
let sdp = "v=0\r\n\
o=- 123 456 IN IP4 999.999.999.999\r\n\
s=-\r\n\
t=0 0\r\n";
let result = SessionDescription::parse(sdp);
let _ = result;
}
#[test]
fn test_negative_timing() {
let sdp = "v=0\r\n\
o=- 123 456 IN IP4 192.168.1.1\r\n\
s=-\r\n\
t=-1 -1\r\n";
let result = SessionDescription::parse(sdp);
let _ = result;
}
#[test]
fn test_invalid_media_port() {
let sdp = "v=0\r\n\
o=- 123 456 IN IP4 192.168.1.1\r\n\
s=-\r\n\
t=0 0\r\n\
m=audio 99999 RTP/AVP 0\r\n";
let result = SessionDescription::parse(sdp);
let _ = result;
}
#[test]
fn test_excessive_media_descriptions() {
let mut sdp = "v=0\r\n\
o=- 123 456 IN IP4 192.168.1.1\r\n\
s=-\r\n\
t=0 0\r\n"
.to_string();
for i in 0..1000 {
sdp.push_str(&format!("m=audio {} RTP/AVP 0\r\n", 10000 + i));
}
let result = SessionDescription::parse(&sdp);
let _ = result;
}
#[test]
fn test_sdp_null_bytes() {
let sdp = b"v=0\r\n\
o=- 123 456 IN IP4 192.168.1.1\r\n\
s=\x00injection\r\n\
t=0 0\r\n";
let result = SessionDescription::parse(std::str::from_utf8(sdp).unwrap_or(""));
let _ = result;
}
}
mod rtp_security {
use super::*;
#[test]
fn test_rtp_truncated_header() {
let data = [0x80, 0x00, 0x00, 0x01]; let result = RtpPacket::parse(&data);
assert!(matches!(result, Err(RtpParseError::TooShort(_))));
}
#[test]
fn test_rtp_invalid_version() {
let data = [
0xC0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa,
];
let result = RtpPacket::parse(&data);
assert!(matches!(result, Err(RtpParseError::InvalidVersion(_))));
}
#[test]
fn test_rtp_excessive_csrc() {
let data = [
0x8F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30,
0x39, ];
let result = RtpPacket::parse(&data);
assert!(result.is_err());
}
#[test]
fn test_rtp_malformed_extension() {
let data = [
0x90, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xAB, 0xCD, ];
let result = RtpPacket::parse(&data);
assert!(matches!(result, Err(RtpParseError::ExtensionTruncated)));
}
#[test]
fn test_rtp_invalid_padding() {
let data = [
0xA0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa, 0xFF, ];
let result = RtpPacket::parse(&data);
assert!(result.is_err() || result.is_ok()); }
#[test]
fn test_rtp_empty_packet() {
let data = [];
let result = RtpPacket::parse(&data);
assert!(matches!(result, Err(RtpParseError::TooShort(0))));
}
#[test]
fn test_rtp_max_size() {
let mut data = vec![
0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30,
0x39, ];
data.extend(vec![0xAA; 1400]);
let result = RtpPacket::parse(&data);
assert!(result.is_ok());
if let Ok(packet) = result {
assert_eq!(packet.payload.len(), 1400);
}
}
#[test]
fn test_rtp_extension_length_overflow() {
let data = [
0x90, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xAB, 0xCD, 0xFF, 0xFF, ];
let result = RtpPacket::parse(&data);
assert!(matches!(result, Err(RtpParseError::ExtensionTruncated)));
}
}
mod boundary_conditions {
use super::*;
#[test]
fn test_exact_boundary_rtp() {
let data = [
0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30,
0x39, ];
let result = RtpPacket::parse(&data);
assert!(result.is_ok());
if let Ok(packet) = result {
assert_eq!(packet.payload.len(), 0);
}
}
#[test]
fn test_off_by_one_rtp() {
let data = [
0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00,
0x30, ];
let result = RtpPacket::parse(&data);
assert!(matches!(result, Err(RtpParseError::TooShort(_))));
}
#[test]
fn test_max_field_values_rtp() {
let data = [
0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ];
let result = RtpPacket::parse(&data);
assert!(result.is_err());
}
#[test]
fn test_zero_values_rtp() {
let data = [
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
let result = RtpPacket::parse(&data);
assert!(result.is_ok());
}
}