use super::super::*;
use std::io::Cursor;
use proptest::prelude::*;
use std::slice;
mod header {
use super::*;
#[test]
fn default() {
let default : TcpHeader = Default::default();
assert_eq!(0, default.source_port);
assert_eq!(0, default.destination_port);
assert_eq!(0, default.sequence_number);
assert_eq!(0, default.acknowledgment_number);
assert_eq!(5, default.data_offset());
assert_eq!(false, default.ns);
assert_eq!(false, default.fin);
assert_eq!(false, default.syn);
assert_eq!(false, default.rst);
assert_eq!(false, default.psh);
assert_eq!(false, default.ack);
assert_eq!(false, default.ece);
assert_eq!(false, default.urg);
assert_eq!(false, default.cwr);
assert_eq!(0, default.window_size);
assert_eq!(0, default.checksum);
assert_eq!(0, default.urgent_pointer);
assert_eq!(&[0;40][0..0], &default.options()[..]);
}
#[test]
fn eq()
{
let options = [
TcpOptionElement::Timestamp(0x00102030, 0x01112131), TcpOptionElement::SelectiveAcknowledgement((0x02122232,0x03132333), [None, None, None]), TcpOptionElement::Timestamp(0x04142434, 0x05152535), TcpOptionElement::Timestamp(0x06162636, 0x07172737), ];
let base : TcpHeader = {
let mut base : TcpHeader = Default::default();
base.source_port = 1;
base.destination_port = 2;
base.sequence_number = 3;
base.acknowledgment_number = 4;
base.window_size = 6;
base.checksum = 7;
base.urgent_pointer = 8;
base.set_options(&options[..]).unwrap();
base
};
{
let other = base.clone();
assert_eq!(other, base);
}
{
let mut other = base.clone();
other.source_port = 10;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.destination_port = 10;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.sequence_number = 10;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.acknowledgment_number = 10;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.set_options(&[TcpOptionElement::MaximumSegmentSize(16)]).unwrap();
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.ns = true;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.fin = true;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.syn = true;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.rst = true;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.psh = true;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.ack = true;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.ece = true;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.urg = true;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.cwr = true;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.window_size = 10;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.checksum = 10;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.urgent_pointer = 10;
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.set_options(&{
let mut other_options = options.clone();
other_options[0] = TcpOptionElement::Timestamp(0x00102039, 0x01112131);
other_options
}).unwrap();
assert_ne!(other, base);
}
{
let mut other = base.clone();
other.set_options(&options).unwrap();
let mut other2 = base.clone();
other2.set_options(&{
let mut options2 = options.clone();
options2[3] = TcpOptionElement::Timestamp(0x06162636, 0x97172737);
options2
}).unwrap();
assert_ne!(other, other2);
}
{
let mut other = base.clone();
other.set_options(&options).unwrap();
let mut other2 = base.clone();
other2.set_options(&{
let mut options2 = options.clone();
options2[3] = TcpOptionElement::Timestamp(0x06162636, 0x97172737);
options2
}).unwrap();
let new_options = [
TcpOptionElement::Timestamp(0x00102030, 0x01112131)
];
other.set_options(&new_options).unwrap();
other2.set_options(&new_options).unwrap();
assert_eq!(other, other2);
}
{
let header = base.clone();
let buffer = {
let mut buffer = Vec::with_capacity(header.header_len().into());
header.write(&mut buffer).unwrap();
buffer
};
let slice = TcpHeaderSlice::from_slice(&buffer).unwrap();
assert_eq!(slice, slice.clone());
}
{
use TcpOptionReadError::*;
let value = UnexpectedEndOfSlice{
option_id: 123,
expected_len: 5,
actual_len: 4,
};
assert_eq!(value, value.clone());
}
{
use TcpOptionWriteError::*;
let value = NotEnoughSpace(123);
assert_eq!(value, value.clone());
}
{
use tcp_option::*;
let it = TcpOptionsIterator::from_slice(&[
KIND_END
]);
assert_eq!(it, it.clone());
}
}
#[test]
fn debug()
{
{
let header: TcpHeader = Default::default();
assert_eq!(
format!(
"TcpHeader {{ source_port: {}, destination_port: {}, sequence_number: {}, acknowledgment_number: {}, data_offset: {}, ns: {}, fin: {}, syn: {}, rst: {}, psh: {}, ack: {}, urg: {}, ece: {}, cwr: {}, window_size: {}, checksum: {}, urgent_pointer: {}, options: [] }}",
header.source_port,
header.destination_port,
header.sequence_number,
header.acknowledgment_number,
header.data_offset(),
header.ns,
header.fin,
header.syn,
header.rst,
header.psh,
header.ack,
header.urg,
header.ece,
header.cwr,
header.window_size,
header.checksum,
header.urgent_pointer
),
format!("{:?}", header)
);
assert_eq!(
format!(
"TcpHeader {{
source_port: {},
destination_port: {},
sequence_number: {},
acknowledgment_number: {},
data_offset: {},
ns: {},
fin: {},
syn: {},
rst: {},
psh: {},
ack: {},
urg: {},
ece: {},
cwr: {},
window_size: {},
checksum: {},
urgent_pointer: {},
options: [],
}}",
header.source_port,
header.destination_port,
header.sequence_number,
header.acknowledgment_number,
header.data_offset(),
header.ns,
header.fin,
header.syn,
header.rst,
header.psh,
header.ack,
header.urg,
header.ece,
header.cwr,
header.window_size,
header.checksum,
header.urgent_pointer
),
format!("{:#?}", header)
);
}
{
let header: TcpHeader = Default::default();
println!("{:?}", header);
let buffer = {
let mut buffer = Vec::with_capacity(header.header_len().into());
header.write(&mut buffer).unwrap();
buffer
};
let slice = TcpHeaderSlice::from_slice(&buffer).unwrap();
println!("{:?}", slice);
assert_eq!(slice, slice.clone());
}
{
use TcpOptionElement::*;
assert_eq!("Noop", format!("{:?}", Noop));
assert_eq!(
"MaximumSegmentSize(123)",
format!("{:?}", MaximumSegmentSize(123))
);
assert_eq!(
"WindowScale(123)",
format!("{:?}", WindowScale(123))
);
assert_eq!(
"SelectiveAcknowledgementPermitted",
format!("{:?}", SelectiveAcknowledgementPermitted)
);
assert_eq!(
"SelectiveAcknowledgement((1, 2), [Some((3, 4)), Some((5, 6)), None])",
format!("{:?}",
SelectiveAcknowledgement((1, 2), [Some((3,4)), Some((5,6)), None])
)
);
assert_eq!(
"Timestamp(123, 456)",
format!("{:?}", Timestamp(123,456))
);
}
{
use TcpOptionReadError::*;
assert_eq!(
"UnexpectedEndOfSlice { option_id: 1, expected_len: 2, actual_len: 3 }",
format!(
"{:?}",
UnexpectedEndOfSlice{
option_id: 1,
expected_len: 2,
actual_len: 3
}
)
);
}
{
use TcpOptionWriteError::*;
assert_eq!(
"NotEnoughSpace(0)",
format!("{:?}", NotEnoughSpace(0))
);
}
{
use tcp_option::*;
assert_eq!(
"[MaximumSegmentSize(0), WindowScale(0)]",
format!(
"{:?}",
TcpOptionsIterator::from_slice(&[
KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0,
KIND_WINDOW_SCALE, 3, 0, KIND_END,
])
)
);
assert_eq!(
"[MaximumSegmentSize(0), Err(UnexpectedSize { option_id: 3, size: 0 })]",
format!(
"{:?}",
TcpOptionsIterator::from_slice(&[
KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0,
KIND_WINDOW_SCALE, 0, 0, 0,
])
)
);
}
}
#[test]
fn options() {
let base : TcpHeader = Default::default();
let dummy = [ 1, 2, 3, 4, 5,
6, 7, 8, 9,10,
11,12,13,14,15,
16,17,18,19,20,
21,22,23,24,25,
26,27,28,29,30,
31,32,33,34,35,
36,37,38,39,40,
41 ];
for i in 0..40 {
let mut header = base.clone();
header.set_options_raw(&dummy[..i]).unwrap();
let mut options_length = i / 4;
if i % 4 != 0 {
options_length += 1;
}
options_length = options_length * 4;
let mut expected_options = [0;40];
expected_options[..i].copy_from_slice(&dummy[..i]);
assert_eq!(options_length, header.options_len());
assert_eq!((options_length / 4) as u8 + TCP_MINIMUM_DATA_OFFSET, header.data_offset());
assert_eq!(&expected_options[..options_length], header.options());
}
let mut header = base.clone();
use crate::TcpOptionWriteError::*;
assert_eq!(Err(NotEnoughSpace(dummy.len())), header.set_options_raw(&dummy[..]));
}
fn write_options(elements: &[TcpOptionElement]) -> TcpHeader {
let mut result : TcpHeader = Default::default();
result.set_options(elements).unwrap();
result
}
proptest! {
#[test]
fn set_options_maximum_segment_size(arg in any::<u16>()) {
use crate::TcpOptionElement::*;
assert_eq!(write_options(&[Noop, Noop, MaximumSegmentSize(arg), Noop]).options(),
&{
use tcp_option::*;
let arg_be = arg.to_be_bytes();
[
KIND_NOOP, KIND_NOOP, KIND_MAXIMUM_SEGMENT_SIZE, 4,
arg_be[0], arg_be[1], KIND_NOOP, KIND_END
]
}
);
}
}
proptest! {
#[test]
fn set_options_window_scale(arg in any::<u8>()) {
use crate::TcpOptionElement::*;
use tcp_option::*;
assert_eq!(write_options(&[Noop, Noop, WindowScale(arg), Noop]).options(),
&[
KIND_NOOP, KIND_NOOP, KIND_WINDOW_SCALE, 3,
arg, KIND_NOOP, KIND_END, 0
]
);
}
}
#[test]
fn set_options_selective_ack_perm() {
use crate::TcpOptionElement::*;
use tcp_option::*;
assert_eq!(write_options(&[Noop, Noop, SelectiveAcknowledgementPermitted, Noop]).options(),
&[
KIND_NOOP, KIND_NOOP, KIND_SELECTIVE_ACK_PERMITTED, 2,
KIND_NOOP, KIND_END, 0, 0
]
);
}
proptest! {
#[test]
fn set_options_selective_ack(args in proptest::collection::vec(any::<u32>(), 4*2)) {
use crate::TcpOptionElement::*;
use tcp_option::*;
let args_be : Vec<[u8;4]> = args.iter().map(|v| v.to_be_bytes()).collect();
assert_eq!(
write_options(&[Noop, Noop, SelectiveAcknowledgement((args[0], args[1]), [None, None, None]), Noop]).options(),
&[
KIND_NOOP, KIND_NOOP, KIND_SELECTIVE_ACK, 10,
args_be[0][0], args_be[0][1], args_be[0][2], args_be[0][3],
args_be[1][0], args_be[1][1], args_be[1][2], args_be[1][3],
KIND_NOOP, KIND_END, 0, 0
]
);
assert_eq!(
write_options(
&[
Noop,
Noop,
SelectiveAcknowledgement(
(args[0], args[1]),
[Some((args[2], args[3])), None, None]
),
Noop
]
).options(),
[
KIND_NOOP, KIND_NOOP, KIND_SELECTIVE_ACK, 18,
args_be[0][0], args_be[0][1], args_be[0][2], args_be[0][3],
args_be[1][0], args_be[1][1], args_be[1][2], args_be[1][3],
args_be[2][0], args_be[2][1], args_be[2][2], args_be[2][3],
args_be[3][0], args_be[3][1], args_be[3][2], args_be[3][3],
KIND_NOOP, KIND_END, 0, 0
]
);
assert_eq!(
write_options(
&[
Noop,
Noop,
SelectiveAcknowledgement(
(args[0], args[1]),
[
Some((args[2], args[3])),
Some((args[4], args[5])),
None
]
),
Noop
]
).options(),
&[
KIND_NOOP, KIND_NOOP, KIND_SELECTIVE_ACK, 26,
args_be[0][0], args_be[0][1], args_be[0][2], args_be[0][3],
args_be[1][0], args_be[1][1], args_be[1][2], args_be[1][3],
args_be[2][0], args_be[2][1], args_be[2][2], args_be[2][3],
args_be[3][0], args_be[3][1], args_be[3][2], args_be[3][3],
args_be[4][0], args_be[4][1], args_be[4][2], args_be[4][3],
args_be[5][0], args_be[5][1], args_be[5][2], args_be[5][3],
KIND_NOOP, KIND_END, 0, 0
]
);
assert_eq!(
write_options(
&[
Noop,
Noop,
SelectiveAcknowledgement(
(args[0], args[1]),
[
Some((args[2], args[3])),
Some((args[4], args[5])),
Some((args[6], args[7]))
]
),
Noop
]
).options(),
&[
KIND_NOOP, KIND_NOOP, KIND_SELECTIVE_ACK, 34,
args_be[0][0], args_be[0][1], args_be[0][2], args_be[0][3],
args_be[1][0], args_be[1][1], args_be[1][2], args_be[1][3],
args_be[2][0], args_be[2][1], args_be[2][2], args_be[2][3],
args_be[3][0], args_be[3][1], args_be[3][2], args_be[3][3],
args_be[4][0], args_be[4][1], args_be[4][2], args_be[4][3],
args_be[5][0], args_be[5][1], args_be[5][2], args_be[5][3],
args_be[6][0], args_be[6][1], args_be[6][2], args_be[6][3],
args_be[7][0], args_be[7][1], args_be[7][2], args_be[7][3],
KIND_NOOP, KIND_END, 0, 0
]
);
}
}
proptest! {
#[test]
fn set_options_timestamp(
arg0 in any::<u32>(),
arg1 in any::<u32>()
) {
use crate::TcpOptionElement::*;
use tcp_option::*;
assert_eq!(write_options(&[Noop, Noop, Timestamp(arg0, arg1), Noop]).options(),
&{
let arg0_be = arg0.to_be_bytes();
let arg1_be = arg1.to_be_bytes();
[
KIND_NOOP, KIND_NOOP, KIND_TIMESTAMP, 10,
arg0_be[0], arg0_be[1], arg0_be[2], arg0_be[3],
arg1_be[0], arg1_be[1], arg1_be[2], arg1_be[3],
KIND_NOOP, KIND_END, 0, 0
]
}
);
}
}
#[test]
fn set_option_padding() {
use crate::TcpOptionElement::*;
let mut tcp_header = TcpHeader::default();
tcp_header.set_options(&[MaximumSegmentSize(1400), SelectiveAcknowledgementPermitted, Timestamp(2661445915, 0), Noop, WindowScale(7)]).unwrap(); assert_eq!(40, tcp_header.header_len());
}
#[test]
fn set_options_not_enough_memory_error() {
use crate::TcpOptionElement::*;
assert_eq!(Err(TcpOptionWriteError::NotEnoughSpace(41)),
TcpHeader::default().set_options(
&[MaximumSegmentSize(1), WindowScale(2), SelectiveAcknowledgementPermitted, SelectiveAcknowledgement((3,4), [Some((5,6)), None, None]), Timestamp(5, 6), Noop, Noop, Noop, Noop ]));
assert_eq!(Err(TcpOptionWriteError::NotEnoughSpace(41)),
TcpHeader::default().set_options(
&[Noop, SelectiveAcknowledgement((3,4), [Some((5,6)), Some((5,6)), Some((5,6))]), MaximumSegmentSize(1), Noop,
Noop ]));
assert_eq!(Err(TcpOptionWriteError::NotEnoughSpace(41)),
TcpHeader::default().set_options(
&[Noop, SelectiveAcknowledgement((3,4), [None, None, None]), Timestamp(1,2), Timestamp(1,2), MaximumSegmentSize(1), Noop, Noop, Noop, Noop, Noop, Noop ]));
}
}
proptest! {
#[test]
fn read_write(ref input in tcp_any())
{
let mut buffer: Vec<u8> = Vec::with_capacity(60);
input.write(&mut buffer).unwrap();
assert_eq!(input.data_offset() as usize * 4, buffer.len());
assert_eq!(input.header_len() as usize, buffer.len());
buffer.push(1);
{
let result = TcpHeader::read(&mut Cursor::new(&buffer)).unwrap();
assert_eq!(input, &result);
}
{
let result = TcpHeader::from_slice(&buffer).unwrap();
assert_eq!(input, &result.0);
assert_eq!(&buffer[buffer.len()-1..], result.1);
}
#[allow(deprecated)]
{
let result = TcpHeader::read_from_slice(&buffer).unwrap();
assert_eq!(input, &result.0);
assert_eq!(&buffer[buffer.len()-1..], result.1);
}
}
}
proptest! {
#[test]
fn read_data_offset_too_small(ref input in tcp_any(),
data_offset in 0..TCP_MINIMUM_DATA_OFFSET)
{
let mut buffer: Vec<u8> = Vec::with_capacity(60);
input.write(&mut buffer).unwrap();
buffer[12] = (buffer[12] & 0xf) | ((data_offset << 4) & 0xf0);
assert_matches!(TcpHeader::read(&mut Cursor::new(&buffer)),
Err(ReadError::TcpDataOffsetTooSmall(_)));
}
}
proptest! {
#[test]
fn read_unexpected_eof(ref input in tcp_any())
{
let mut buffer: Vec<u8> = Vec::with_capacity(60);
input.write(&mut buffer).unwrap();
let len = buffer.len() - 1;
assert_matches!(TcpHeader::read(&mut Cursor::new(&buffer[..len])),
Err(ReadError::IoError(_)));
}
}
#[test]
fn write_and_read_length_error() {
let headers = {
let base_header = TcpHeader::new(1234,4567,9876,789);
use TcpOptionElement::*;
[
{
let mut header = base_header.clone();
header.ns = true;
header.fin = true;
header.syn = true;
header.rst = true;
header.psh = true;
header.ack = true;
header.urg = true;
header.ece = true;
header.cwr = true;
header
}, {
let mut header = base_header.clone();
header.set_options(&[
MaximumSegmentSize(111),
WindowScale(222),
SelectiveAcknowledgementPermitted,
Timestamp(12,23)
]).unwrap();
header
}, {
let mut header = base_header.clone();
header.set_options(&[
SelectiveAcknowledgement(
(1,2), [Some((3,4)),Some((5,6)), Some((7,8))]
),
]).unwrap();
header
}
]
};
for header in &headers {
for len in 0..usize::from(header.header_len()) {
let mut writer = TestWriter::with_max_size(len);
assert_eq!(
writer.error_kind(),
header.write(&mut writer).unwrap_err().kind()
);
}
let buffer = {
let mut buffer = Vec::with_capacity(header.header_len().into());
header.write(&mut buffer).unwrap();
buffer
};
for len in 0..buffer.len() {
use ReadError::*;
assert_matches!(
TcpHeader::read(&mut Cursor::new(&buffer[0..len])),
Err(IoError(_))
);
assert_matches!(
TcpHeader::from_slice(&buffer[0..len]),
Err(UnexpectedEndOfSlice(_))
);
assert_matches!(
TcpHeaderSlice::from_slice(&buffer[0..len]),
Err(UnexpectedEndOfSlice(_))
);
}
}
}
proptest! {
#[test]
fn packet_slice_from_slice(ref input in tcp_any()) {
let mut buffer: Vec<u8> = Vec::with_capacity(60);
input.write(&mut buffer).unwrap();
let slice = TcpHeaderSlice::from_slice(&buffer).unwrap();
assert_eq!(input.source_port, slice.source_port());
assert_eq!(input.destination_port, slice.destination_port());
assert_eq!(input.sequence_number, slice.sequence_number());
assert_eq!(input.acknowledgment_number, slice.acknowledgment_number());
assert_eq!(input.data_offset(), slice.data_offset());
assert_eq!(input.ns, slice.ns());
assert_eq!(input.fin, slice.fin());
assert_eq!(input.syn, slice.syn());
assert_eq!(input.rst, slice.rst());
assert_eq!(input.psh, slice.psh());
assert_eq!(input.ack, slice.ack());
assert_eq!(input.ece, slice.ece());
assert_eq!(input.urg, slice.urg());
assert_eq!(input.cwr, slice.cwr());
assert_eq!(input.window_size, slice.window_size());
assert_eq!(input.checksum, slice.checksum());
assert_eq!(input.urgent_pointer, slice.urgent_pointer());
assert_eq!(input.options(), slice.options());
assert_eq!(input, &slice.to_header());
}
}
proptest! {
#[test]
fn packet_slice_from_slice_data_offset_too_small(ref input in tcp_any(),
data_offset in 0..TCP_MINIMUM_DATA_OFFSET)
{
let mut buffer: Vec<u8> = Vec::with_capacity(60);
input.write(&mut buffer).unwrap();
buffer[12] = (buffer[12] & 0xf) | ((data_offset << 4) & 0xf0);
assert_matches!(TcpHeaderSlice::from_slice(&buffer),
Err(ReadError::TcpDataOffsetTooSmall(_)));
}
}
proptest! {
#[test]
fn debug_fmt(ref input in tcp_any())
{
assert_eq!(&format!("TcpHeader {{ source_port: {}, destination_port: {}, sequence_number: {}, acknowledgment_number: {}, data_offset: {}, ns: {}, fin: {}, syn: {}, rst: {}, psh: {}, ack: {}, urg: {}, ece: {}, cwr: {}, window_size: {}, checksum: {}, urgent_pointer: {}, options: {:?} }}",
input.source_port,
input.destination_port,
input.sequence_number,
input.acknowledgment_number,
input.data_offset(),
input.ns,
input.fin,
input.syn,
input.rst,
input.psh,
input.ack,
input.urg,
input.ece,
input.cwr,
input.window_size,
input.checksum,
input.urgent_pointer,
input.options_iterator(),
),
&format!("{:?}", input)
);
}
}
#[test]
fn calc_header_checksum_ipv4() {
use crate::TcpOptionElement::*;
{
let tcp_payload = [1,2,3,4,5,6,7,8];
let tcp = TcpHeader::new(
0,
0,
40905,
0
);
let ip_header = Ipv4Header::new(
tcp.header_len() + (tcp_payload.len() as u16),
0,
ip_number::TCP,
[0;4],
[0;4]
);
assert_eq!(Ok(0x0), tcp.calc_checksum_ipv4(&ip_header, &tcp_payload));
assert_eq!(Ok(0x0), tcp.calc_checksum_ipv4_raw(ip_header.source, ip_header.destination, &tcp_payload));
}
{
let tcp_payload = [1,2,3,4,5,6,7,8];
let mut tcp = TcpHeader::new(
69,
42,
0x24900448,
0x3653
);
tcp.urgent_pointer = 0xE26E;
tcp.ns = true;
tcp.fin = true;
tcp.syn = true;
tcp.rst = true;
tcp.psh = true;
tcp.ack = true;
tcp.ece = true;
tcp.urg = true;
tcp.cwr = true;
tcp.set_options(&[
Noop, Noop, Noop, Noop,
Timestamp(0x4161008, 0x84161708)
]).unwrap();
let ip_header = Ipv4Header::new(
tcp.header_len() + (tcp_payload.len() as u16),
20,
ip_number::TCP,
[192,168,1,42],
[192,168,1,1]
);
assert_eq!(Ok(0xdeeb), tcp.calc_checksum_ipv4(&ip_header, &tcp_payload));
assert_eq!(Ok(0xdeeb), tcp.calc_checksum_ipv4_raw(ip_header.source, ip_header.destination, &tcp_payload));
let mut ip_buffer = Vec::new();
ip_header.write(&mut ip_buffer).unwrap();
let ip_slice = Ipv4HeaderSlice::from_slice(&ip_buffer[..]).unwrap();
let mut tcp_buffer = Vec::new();
tcp.write(&mut tcp_buffer).unwrap();
let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap();
assert_eq!(Ok(0xdeeb), tcp_slice.calc_checksum_ipv4(&ip_slice, &tcp_payload));
assert_eq!(Ok(0xdeeb), tcp_slice.calc_checksum_ipv4_raw(ip_slice.source(), ip_slice.destination(), &tcp_payload));
}
{
let tcp_payload = [1,2,3,4,5,6,7,8,9];
let mut tcp = TcpHeader::new(
69,
42,
0x24900448,
0x3653
);
tcp.urgent_pointer = 0xE26E;
tcp.ns = true;
tcp.fin = true;
tcp.syn = true;
tcp.rst = true;
tcp.psh = true;
tcp.ack = true;
tcp.ece = true;
tcp.urg = true;
tcp.cwr = true;
tcp.set_options(&[
Noop, Noop, Noop, Noop,
Timestamp(0x4161008, 0x84161708)
]).unwrap();
let ip_header = Ipv4Header::new(
tcp.header_len() + (tcp_payload.len() as u16),
20,
ip_number::TCP,
[192,168,1,42],
[192,168,1,1]
);
assert_eq!(Ok(0xd5ea), tcp.calc_checksum_ipv4(&ip_header, &tcp_payload));
assert_eq!(Ok(0xd5ea), tcp.calc_checksum_ipv4_raw(ip_header.source, ip_header.destination, &tcp_payload));
let mut ip_buffer = Vec::new();
ip_header.write(&mut ip_buffer).unwrap();
let ip_slice = Ipv4HeaderSlice::from_slice(&ip_buffer[..]).unwrap();
let mut tcp_buffer = Vec::new();
tcp.write(&mut tcp_buffer).unwrap();
let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap();
assert_eq!(Ok(0xd5ea), tcp_slice.calc_checksum_ipv4(&ip_slice, &tcp_payload));
assert_eq!(Ok(0xd5ea), tcp_slice.calc_checksum_ipv4_raw(ip_slice.source(), ip_slice.destination(), &tcp_payload));
}
}
#[test]
fn calc_header_checksum_ipv6() {
let tcp_payload = [51,52,53,54,55,56,57,58];
let mut tcp = TcpHeader::new(
69,
42,
0x24900448,
0x3653
);
tcp.urgent_pointer = 0xE26E;
tcp.ns = true;
tcp.fin = true;
tcp.syn = true;
tcp.rst = true;
tcp.psh = true;
tcp.ack = true;
tcp.ece = true;
tcp.urg = true;
tcp.cwr = true;
use crate::TcpOptionElement::*;
tcp.set_options(&[
Noop, Noop, Noop, Noop,
Timestamp(0x4161008, 0x84161708)
]).unwrap();
let ip_header = Ipv6Header {
traffic_class: 1,
flow_label: 0x81806,
payload_length: tcp_payload.len() as u16 + tcp.header_len(),
next_header: ip_number::TCP,
hop_limit: 40,
source: [1,2,3,4,5,6,7,8,
9,10,11,12,13,14,15,16],
destination: [21,22,23,24,25,26,27,28,
29,30,31,32,33,34,35,36]
};
assert_eq!(Ok(0x786e), tcp.calc_checksum_ipv6(&ip_header, &tcp_payload));
assert_eq!(Ok(0x786e), tcp.calc_checksum_ipv6_raw(ip_header.source, ip_header.destination, &tcp_payload));
let mut ip_buffer = Vec::new();
ip_header.write(&mut ip_buffer).unwrap();
let ip_slice = Ipv6HeaderSlice::from_slice(&ip_buffer[..]).unwrap();
let mut tcp_buffer = Vec::new();
tcp.write(&mut tcp_buffer).unwrap();
let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap();
assert_eq!(Ok(0x786e), tcp_slice.calc_checksum_ipv6(&ip_slice, &tcp_payload));
assert_eq!(Ok(0x786e), tcp_slice.calc_checksum_ipv6_raw(ip_slice.source(), ip_slice.destination(), &tcp_payload));
}
#[test]
fn calc_header_checksum_ipv4_error() {
let tcp: TcpHeader = Default::default();
let len = (std::u16::MAX - tcp.header_len()) as usize + 1;
let mut tcp_payload = Vec::with_capacity(len);
tcp_payload.resize(len, 0);
let ip_header = Ipv4Header::new(0, 0, ip_number::TCP, [0;4], [0;4]);
assert_eq!(Err(ValueError::TcpLengthTooLarge(std::u16::MAX as usize + 1)), tcp.calc_checksum_ipv4(&ip_header, &tcp_payload));
assert_eq!(Err(ValueError::TcpLengthTooLarge(std::u16::MAX as usize + 1)), tcp.calc_checksum_ipv4_raw(ip_header.source, ip_header.destination, &tcp_payload));
let mut ip_buffer = Vec::new();
ip_header.write(&mut ip_buffer).unwrap();
let ip_slice = Ipv4HeaderSlice::from_slice(&ip_buffer[..]).unwrap();
let mut tcp_buffer = Vec::new();
tcp.write(&mut tcp_buffer).unwrap();
let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap();
assert_eq!(Err(ValueError::TcpLengthTooLarge(std::u16::MAX as usize + 1)), tcp_slice.calc_checksum_ipv4(&ip_slice, &tcp_payload));
assert_eq!(Err(ValueError::TcpLengthTooLarge(std::u16::MAX as usize + 1)), tcp_slice.calc_checksum_ipv4_raw(ip_slice.source(), ip_slice.destination(), &tcp_payload));
}
#[test]
#[cfg(target_pointer_width = "64")]
fn calc_header_checksum_ipv6_error() {
let tcp: TcpHeader = Default::default();
let len = (std::u32::MAX - tcp.header_len() as u32) as usize +
1;
let tcp_payload = unsafe {
use std::ptr::NonNull;
slice::from_raw_parts(
NonNull::<u8>::dangling().as_ptr(),
len
)
};
let ip_header = Ipv6Header {
traffic_class: 1,
flow_label: 0x81806,
payload_length: 0, next_header: ip_number::TCP,
hop_limit: 40,
source: [1,2,3,4,5,6,7,8,
9,10,11,12,13,14,15,16],
destination: [21,22,23,24,25,26,27,28,
29,30,31,32,33,34,35,36]
};
assert_eq!(Err(ValueError::TcpLengthTooLarge(std::u32::MAX as usize + 1)), tcp.calc_checksum_ipv6(&ip_header, &tcp_payload));
assert_eq!(Err(ValueError::TcpLengthTooLarge(std::u32::MAX as usize + 1)), tcp.calc_checksum_ipv6_raw(ip_header.source, ip_header.destination, &tcp_payload));
let mut ip_buffer = Vec::new();
ip_header.write(&mut ip_buffer).unwrap();
let ip_slice = Ipv6HeaderSlice::from_slice(&ip_buffer[..]).unwrap();
let mut tcp_buffer = Vec::new();
tcp.write(&mut tcp_buffer).unwrap();
let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap();
assert_eq!(Err(ValueError::TcpLengthTooLarge(std::u32::MAX as usize + 1)), tcp_slice.calc_checksum_ipv6(&ip_slice, &tcp_payload));
assert_eq!(Err(ValueError::TcpLengthTooLarge(std::u32::MAX as usize + 1)), tcp_slice.calc_checksum_ipv6_raw(ip_slice.source(), ip_slice.destination(), &tcp_payload));
}
#[test]
fn options_iterator_method() {
let options = [
TcpOptionElement::Timestamp(0x00102030, 0x01112131), TcpOptionElement::SelectiveAcknowledgement((0x02122232,0x03132333), [None, None, None]), TcpOptionElement::Timestamp(0x04142434, 0x05152535), TcpOptionElement::Timestamp(0x06162636, 0x07172737), ];
let base : TcpHeader = {
let mut base : TcpHeader = Default::default();
base.set_options(&options[..]).unwrap();
base
};
assert_eq!(
&options[..],
&base
.options_iterator()
.map(|x| x.unwrap())
.collect::<Vec<TcpOptionElement>>()[..]
);
}
#[test]
fn options_iterator() {
use crate::TcpOptionElement::*;
use tcp_option::*;
let header = {
let mut header : TcpHeader = Default::default();
header.set_options_raw(&[
KIND_NOOP, KIND_NOOP,
KIND_MAXIMUM_SEGMENT_SIZE, 4,
0, 1,
KIND_END, 0, 0, 0
]).unwrap();
header
};
{
let mut it = header.options_iterator();
let expected = [
Noop,
Noop,
MaximumSegmentSize(1),
];
for element in expected.iter() {
assert_eq!(element, &it.next().unwrap().unwrap());
}
assert_eq!(None, it.next());
assert_eq!(0, it.rest().len());
}
{
let mut buffer = Vec::with_capacity(header.header_len().into());
header.write(&mut buffer).unwrap();
let slice = TcpHeaderSlice::from_slice(&buffer).unwrap();
let mut it = slice.options_iterator();
let expected = [
Noop,
Noop,
MaximumSegmentSize(1),
];
for element in expected.iter() {
assert_eq!(element, &it.next().unwrap().unwrap());
}
assert_eq!(None, it.next());
assert_eq!(0, it.rest().len());
}
}
#[test]
fn options_iterator_from_slice() {
fn expect_elements(buffer: &[u8], expected: &[TcpOptionElement]) {
let mut it = TcpOptionsIterator::from_slice(buffer);
for element in expected.iter() {
assert_eq!(element, &it.next().unwrap().unwrap());
}
assert_eq!(None, it.next());
assert_eq!(0, it.rest().len());
}
use crate::TcpOptionElement::*;
use tcp_option::*;
expect_elements(&[
KIND_NOOP,
KIND_NOOP,
KIND_MAXIMUM_SEGMENT_SIZE, 4,
0, 1,
KIND_WINDOW_SCALE, 3, 2,
KIND_SELECTIVE_ACK_PERMITTED, 2,
KIND_SELECTIVE_ACK, 10,
0, 0, 0, 10,
0, 0, 0, 11,
KIND_SELECTIVE_ACK, 18,
0, 0, 0, 12,
0, 0, 0, 13,
0, 0, 0, 14,
0, 0, 0, 15,
KIND_SELECTIVE_ACK, 26,
0, 0, 0, 16,
0, 0, 0, 17,
0, 0, 0, 18,
0, 0, 0, 19,
0, 0, 0, 20,
0, 0, 0, 21,
KIND_SELECTIVE_ACK, 34,
0, 0, 0, 22,
0, 0, 0, 23,
0, 0, 0, 24,
0, 0, 0, 25,
0, 0, 0, 26,
0, 0, 0, 27,
0, 0, 0, 28,
0, 0, 0, 29,
KIND_TIMESTAMP, 10,
0, 0, 0, 30,
0, 0, 0, 31,
KIND_END, 0, 0, 0, 0
],
&[
Noop,
Noop,
MaximumSegmentSize(1),
WindowScale(2),
SelectiveAcknowledgementPermitted,
SelectiveAcknowledgement((10,11), [None, None, None]),
SelectiveAcknowledgement((12,13), [Some((14,15)), None, None]),
SelectiveAcknowledgement((16,17), [Some((18,19)), Some((20,21)), None]),
SelectiveAcknowledgement((22,23), [Some((24,25)), Some((26,27)), Some((28,29))]),
Timestamp(30,31)
]);
}
#[test]
fn options_iterator_unexpected_eos() {
fn expect_unexpected_eos(slice: &[u8]) {
for i in 1..slice.len()-1 {
let mut it = TcpOptionsIterator::from_slice(&slice[..i]);
assert_eq!(
Some(
Err(
TcpOptionReadError::UnexpectedEndOfSlice{
option_id: slice[0],
expected_len: match slice[0] {
KIND_MAXIMUM_SEGMENT_SIZE => 4,
KIND_WINDOW_SCALE => 3,
KIND_SELECTIVE_ACK_PERMITTED => 2,
KIND_SELECTIVE_ACK => if i < 2 {
2
} else {
slice[1]
},
KIND_TIMESTAMP => 10,
_ => panic!("not part of the tests"),
},
actual_len: i
}
)
),
it.next()
);
assert_eq!(0, it.rest().len());
assert_eq!(None, it.next());
}
}
use tcp_option::*;
expect_unexpected_eos(&[KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0]);
expect_unexpected_eos(&[KIND_WINDOW_SCALE, 3, 0]);
expect_unexpected_eos(&[KIND_MAXIMUM_SEGMENT_SIZE, 4, 0, 0]);
expect_unexpected_eos(&[KIND_SELECTIVE_ACK_PERMITTED, 2]);
expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 10, 0, 0, 0,
0, 0, 0, 0, 0]);
expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 18, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0]);
expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 26, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0]);
expect_unexpected_eos(&[KIND_SELECTIVE_ACK, 34, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0]);
expect_unexpected_eos(&[KIND_TIMESTAMP, 10, 0, 0, 0,
0, 0, 0, 0, 0]);
}
#[test]
fn options_iterator_unexpected_length() {
fn expect_unexpected_size(id: u8, size: u8) {
let data = [id, size, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0];
let mut it = TcpOptionsIterator::from_slice(&data);
assert_eq!(Some(Err(TcpOptionReadError::UnexpectedSize {option_id: data[0], size: data[1] })), it.next());
assert_eq!(0, it.rest().len());
assert_eq!(None, it.next());
assert_eq!(0, it.rest().len());
}
use tcp_option::*;
expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 3);
expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 5);
expect_unexpected_size(KIND_WINDOW_SCALE, 2);
expect_unexpected_size(KIND_WINDOW_SCALE, 4);
expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 3);
expect_unexpected_size(KIND_MAXIMUM_SEGMENT_SIZE, 5);
expect_unexpected_size(KIND_SELECTIVE_ACK_PERMITTED, 1);
expect_unexpected_size(KIND_SELECTIVE_ACK_PERMITTED, 3);
expect_unexpected_size(KIND_SELECTIVE_ACK, 9);
expect_unexpected_size(KIND_SELECTIVE_ACK, 11);
expect_unexpected_size(KIND_SELECTIVE_ACK, 17);
expect_unexpected_size(KIND_SELECTIVE_ACK, 19);
expect_unexpected_size(KIND_SELECTIVE_ACK, 25);
expect_unexpected_size(KIND_SELECTIVE_ACK, 27);
expect_unexpected_size(KIND_SELECTIVE_ACK, 33);
expect_unexpected_size(KIND_SELECTIVE_ACK, 35);
expect_unexpected_size(KIND_TIMESTAMP, 9);
expect_unexpected_size(KIND_TIMESTAMP, 11);
}
#[test]
fn options_iterator_unexpected_id() {
let data = [255, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0];
let mut it = TcpOptionsIterator::from_slice(&data);
assert_eq!(Some(Err(TcpOptionReadError::UnknownId(255))), it.next());
assert_eq!(0, it.rest().len());
assert_eq!(None, it.next());
assert_eq!(0, it.rest().len());
}
#[test]
fn options_iterator_debug() {
fn expect_elements(buffer: &[u8], expected: &[TcpOptionElement]) {
let mut it = TcpOptionsIterator::from_slice(buffer);
for element in expected.iter() {
assert_eq!(element, &it.next().unwrap().unwrap());
}
assert_eq!(None, it.next());
assert_eq!(0, it.rest().len());
}
use crate::TcpOptionElement::*;
use tcp_option::*;
expect_elements(&[
KIND_NOOP,
KIND_NOOP,
KIND_MAXIMUM_SEGMENT_SIZE, 4,
0, 1,
KIND_WINDOW_SCALE, 3, 2,
KIND_SELECTIVE_ACK_PERMITTED, 2,
KIND_SELECTIVE_ACK, 10,
0, 0, 0, 10,
0, 0, 0, 11,
KIND_SELECTIVE_ACK, 18,
0, 0, 0, 12,
0, 0, 0, 13,
0, 0, 0, 14,
0, 0, 0, 15,
KIND_SELECTIVE_ACK, 26,
0, 0, 0, 16,
0, 0, 0, 17,
0, 0, 0, 18,
0, 0, 0, 19,
0, 0, 0, 20,
0, 0, 0, 21,
KIND_SELECTIVE_ACK, 34,
0, 0, 0, 22,
0, 0, 0, 23,
0, 0, 0, 24,
0, 0, 0, 25,
0, 0, 0, 26,
0, 0, 0, 27,
0, 0, 0, 28,
0, 0, 0, 29,
KIND_TIMESTAMP, 10,
0, 0, 0, 30,
0, 0, 0, 31,
KIND_END, 0, 0, 0, 0
],
&[
Noop,
Noop,
MaximumSegmentSize(1),
WindowScale(2),
SelectiveAcknowledgementPermitted,
SelectiveAcknowledgement((10,11), [None, None, None]),
SelectiveAcknowledgement((12,13), [Some((14,15)), None, None]),
SelectiveAcknowledgement((16,17), [Some((18,19)), Some((20,21)), None]),
SelectiveAcknowledgement((22,23), [Some((24,25)), Some((26,27)), Some((28,29))]),
Timestamp(30,31)
]
);
}
proptest! {
#[test]
fn tcp_options_read_error_display(
arg_u8_0 in any::<u8>(),
arg_u8_1 in any::<u8>(),
arg_usize in any::<usize>()
) {
use crate::TcpOptionReadError::*;
assert_eq!(
&format!("TcpOptionReadError: Not enough memory left in slice to read option of kind {} (expected at least {} bytes, only {} bytes available).", arg_u8_0, arg_u8_1, arg_usize),
&format!("{}", UnexpectedEndOfSlice{ option_id: arg_u8_0, expected_len: arg_u8_1, actual_len: arg_usize})
);
assert_eq!(
&format!("TcpOptionReadError: Length value of the option of kind {} had unexpected value {}.", arg_u8_0, arg_u8_1),
&format!("{}", UnexpectedSize{ option_id: arg_u8_0, size: arg_u8_1 })
);
assert_eq!(
&format!("TcpOptionReadError: Unknown tcp option kind value {}.", arg_u8_0),
&format!("{}", UnknownId(arg_u8_0))
);
}
}
proptest! {
#[test]
fn tcp_options_read_error_source(
arg_u8_0 in any::<u8>(),
arg_u8_1 in any::<u8>(),
arg_usize in any::<usize>()
) {
use std::error::Error;
use crate::TcpOptionReadError::*;
assert!(UnexpectedEndOfSlice{ option_id: arg_u8_0, expected_len: arg_u8_1, actual_len: arg_usize}.source().is_none());
assert!(UnexpectedSize{ option_id: arg_u8_0, size: arg_u8_1 }.source().is_none());
assert!(UnknownId(arg_u8_0).source().is_none());
}
}
proptest! {
#[test]
fn tcp_options_write_error_display(
arg_usize in any::<usize>()
) {
use crate::TcpOptionWriteError::*;
assert_eq!(
&format!("TcpOptionWriteError: Not enough memory to store all options in the options section of a tcp header (maximum 40 bytes can be stored, the options would have needed {} bytes).", arg_usize),
&format!("{}", NotEnoughSpace(arg_usize))
);
}
}
proptest! {
#[test]
fn tcp_options_write_error_source(
arg_usize in any::<usize>()
) {
use std::error::Error;
use crate::TcpOptionWriteError::*;
assert!(NotEnoughSpace(arg_usize).source().is_none());
}
}